并行的扩展

扩展1.

Parallel的使用:

在Parallel下面有三个常用的方法Invoke,For,ForEach

Parallel.Invoke()方法是最简单,最简洁的将串行的代码并行化.

在这里先说一点,就是Stopwatch的使用,Stopwatch到底是个什么东西,首先Stopwatch在命名空间System.Diagnostics中.

使用方法如下:

var StopWatch =new Stopwatch();//创建一个Stopwatch实例

StopWatch.Start();//开始计时

StopWatch.Stop();//停止计时

StopWatch.Reset();//重置StopWatch

StopWatch.Restart();//重启被停止的Stopwatch

stopWatch.ElapsedMilliseconds //获取stopWatch从开始到现在的时间差,单位是毫秒

案例:

using System;

using System.Collections.Concurrent;

using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;

using System.Text;

using System.Threading;

using System.Threading.Tasks;

namespace 并行集合和LINQ

{

class Program

{

static void Main(string[] args)

{

Custom custom = new Custom();

custom.ParallelInvokeMethod();

Console.WriteLine("运行完成");

Console.ReadKey();

}

}

public class Custom

{

private Stopwatch stopWatch = new Stopwatch();

public void Run1()

{

Thread.Sleep(2000);//Thread需要添加命名空间

Console.WriteLine("Task 1 is cost 2 sec");

}

public void Run2()

{

Thread.Sleep(3000);

Console.WriteLine("Task 2 is cost 3 sec");

}

public void ParallelInvokeMethod()

{

stopWatch.Start();

Parallel.Invoke(Run1, Run2);

stopWatch.Stop();

Console.WriteLine("Parallel run " + stopWatch.ElapsedMilliseconds + " ms.");//这是在并行的情况下

stopWatch.Restart();

Run1();

Run2();

stopWatch.Stop();

Console.WriteLine("Normal run " + stopWatch.ElapsedMilliseconds + " ms.");//这是正常情况

}

}

}

分析:正确情况下确实应该是5秒左右,明明白白写着呢,3000+2000=5000ms,而使用了Parallel.Invoke方法只用了3秒,由此可见并行执行提高了很多效率.

扩展2:Parallel.For

这个方法和For循环的功能类似,案例:

using System;

using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace 并行扩展

{

class Program

{

static void Main(string[] args)

{

Stopwatch stopWatch = new Stopwatch();

stopWatch.Start();

for (int i = 0; i < 10000; i++)

{

for (int j = 0; j < 60000; j++)

{

int sum = 0;

sum += i;

}

}

stopWatch.Stop();

Console.WriteLine("NormalFor run " + stopWatch.ElapsedMilliseconds + " ms.");

stopWatch.Reset();

stopWatch.Start();

Parallel.For(0, 10000, item =>

{

for (int j = 0; j < 60000; j++)

{

int sum = 0;

sum += item;

}

});

stopWatch.Stop();

Console.WriteLine("ParallelFor run " + stopWatch.ElapsedMilliseconds + " ms.");

Console.WriteLine("运行完毕");

Console.ReadKey();

}

}

}

分析:写了两个循环,做些无用的操作,主要是消耗CPU的资源,通过多次运行结果可以看到们使用了Parallel.For所有的时间差不多也就是单纯for时间的三分之一.是不是在任何时候Parallel.For在任何时候都比这普通的for快呢,肯定不是啊,要是这样的话,C#的for早就淘汰了.

案例:修改代码,添加一个全局变量num

using System;

using System.Collections.Concurrent;

using System.Collections.Generic;

using System.Diagnostics;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace 并行扩展

{

class Program

{

static void Main(string[] args)

{

Stopwatch stopWatch = new Stopwatch();

var obj = new Object();

long num = 0;

ConcurrentBag<long> bag = new ConcurrentBag<long>();

stopWatch.Start();

for (int i = 0; i < 10000; i++)

{

for (int j = 0; j < 60000; j++)

{

//int sum = 0;

//sum += item;

num++;

}

}

stopWatch.Stop();

Console.WriteLine("NormalFor run " + stopWatch.ElapsedMilliseconds + " ms.");

stopWatch.Reset();

stopWatch.Start();

Parallel.For(0, 10000, item =>

{

for (int j = 0; j < 60000; j++)

{

//int sum = 0;

//sum += item;

lock (obj)

{

num++;

}

}

});

stopWatch.Stop();

Console.WriteLine("ParallelFor run " + stopWatch.ElapsedMilliseconds + " ms.");

//并行的问题,需要多运行几遍,一遍两遍看不出什么东西来

Console.WriteLine("运行完毕");

Console.ReadKey();

}

}

}

分析:Parallel.For由于是并行运行的,所以会同时访问访问全局变量num,为了得到正确的结果,要使用lock,所以Parallel.For竟然耗了这么多时间,这是因为并行同时访问全局变量,会出现资源争夺(我的电脑当时开着虚拟机,听着音乐,在程序运行的时候我我Ctrl+S了以下文档,我的电脑出现卡死的情况),大不多的资源都消耗在了资源等待上面.

虽然一直说并说,但一直没有证明一下,你肯定不服,来让你服气:

Parallel.For(0, 100, i =>

{

Console.Write(i + "\t");

});

Console.WriteLine("运行完毕");

从0输出到99,运行后会发现输出的顺序不对,用for顺序肯定是对的,并行同时执行,所以会出现输出顺序不同的情况。

扩展3

Parallel.ForEach

这个方法和普通的foreach很相似,案例:

List<int> list = new List<int>();

for (int i = 0; i < 100000; i++)

{

list.Add(i);

}

Stopwatch stopWatch = new Stopwatch();

stopWatch.Start();

Parallel.ForEach(list, i =>

{

i++;

});

stopWatch.Stop();

Console.WriteLine(stopWatch.ElapsedMilliseconds);

Parallel中途退出循环和异常处理

我们为啥使用Parallel呢,肯定是在处理一些比较好使的任务,当然也很消耗CPU资源和内存,如果我们在中途想停止,怎么办呢?

串行好办啊,一个break搞定,但是串行呢?貌似不知道呢,在并行循环的委托参数中提供了一个ParallelLoopState,该实例提供了Break和Stop方法来帮助我们!

Break: 当然这个是通知并行计算尽快的退出循环,比如并行计算正在迭代100,那么break后程序还会迭代所有小于100的。

Stop:这个就不一样了,比如正在迭代100突然遇到stop,那它啥也不管了,直接退出。

案例:

Stopwatch stopWatch = new Stopwatch();

ConcurrentBag<int> bag = new ConcurrentBag<int>();

stopWatch.Start();

Parallel.For(0, 1000, (i, state) =>

{

if (bag.Count == 300)

{

//state.Stop();//也可能会出现300多,但是不会很夸张,在我的测试下,最多出现303,大部分还是300

state.Break();//如果是break的话,可能会看到Bag count is 300(多),在我多次测试下,得到最夸张的结果是840

return;

}

bag.Add(i);

});

stopWatch.Stop();

Console.WriteLine("Bag count is " + bag.Count + ", " + "一共用时 :"+stopWatch.ElapsedMilliseconds+"ms");

Console.WriteLine("运行完毕");

Console.ReadKey();

异常:

首先任务是并行计算的,处理过程中可能会产生n多的异常,那么如何来获取到这些异常呢?普通的Exception并不能获取到异常,然而为并行诞生的AggregateExcepation就可以获取到一组异常。

这里我们修改Parallel.Invoke的代码,修改后代码如下:

private Stopwatch stopWatch = new Stopwatch();

public void Run1()

{

Thread.Sleep(2000);

Console.WriteLine("Task 1 is cost 2 sec");

throw new Exception("Exception in task 1");

}

public void Run2()

{

Thread.Sleep(3000);

Console.WriteLine("Task 2 is cost 3 sec");

throw new Exception("Exception in task 2");

}

public void ParallelInvokeMethod()

{

stopWatch.Start();

try

{

Parallel.Invoke(Run1, Run2);

}

catch (AggregateException aex)

{

foreach (var ex in aex.InnerExceptions)

{

Console.WriteLine(ex.Message);

}

}

stopWatch.Stop();

Console.WriteLine("Parallel run " + stopWatch.ElapsedMilliseconds + " ms.");

stopWatch.Reset();

stopWatch.Start();

try

{

Run1();

Run2();

}

catch (Exception ex)

{

Console.WriteLine(ex.Message);

}

stopWatch.Stop();

Console.WriteLine("Normal run " + stopWatch.ElapsedMilliseconds + " ms.");

Console.WriteLine("运行完毕");

Console.ReadKey();

C#编程(六十四)----------并行扩展的更多相关文章

  1. Gradle 1.12用户指南翻译——第六十四章. 发布到Ivy(新)

    其他章节的翻译请参见:http://blog.csdn.net/column/details/gradle-translation.html翻译项目请关注Github上的地址:https://gith ...

  2. 孤荷凌寒自学python第六十四天学习mongoDB的基本操作并进行简单封装3

    孤荷凌寒自学python第六十四天学习mongoDB的基本操作并进行简单封装3 (完整学习过程屏幕记录视频地址在文末) 今天是学习mongoDB数据库的第十天. 今天继续学习mongoDB的简单操作, ...

  3. SpringBoot进阶教程(六十四)注解大全

    在Spring1.x时代,还没出现注解,需要大量xml配置文件并在内部编写大量bean标签.Java5推出新特性annotation,为spring的更新奠定了基础.从Spring 2.X开始spri ...

  4. 第三百六十四节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的mapping映射管理

    第三百六十四节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的mapping映射管理 1.映射(mapping)介绍 映射:创建索引的时候,可以预先定义字 ...

  5. “全栈2019”Java第六十四章:接口与静态方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  6. 学习ASP.NET Core Razor 编程系列十四——文件上传功能(二)

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

  7. OpenCV开发笔记(六十四):红胖子8分钟带你深入了解SURF特征点(图文并茂+浅显易懂+程序源码)

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  8. C#高级编程六十九天----DLR简介 .在.NET中使用DLR(转载) 我也来说说Dynamic

    DLR 一.近年来,在TIOBE公司每个月发布的编程语言排行榜中,C#总是能挤进前十名,而在最近十年来,C#总体上呈现上升的趋势.C#能取得这样的成绩,有很多因素,其中它在语言特性上的锐意进取让人印象 ...

  9. 第六十四天 JS基础操作

    一.分支结构 1.if语句 if基础语句 if(条件表达式){ 代码块: } // 当条件表达式结果为true,会执行代码块:反之不执行 // 条件表达式可以为普通表达式 // 0.undefined ...

随机推荐

  1. 深入理解java虚拟机-00

    这本书买了有两年了,只有买回来翻了两页...今天电脑有点卡,游戏玩不了了,就来看看这本书. 首先看了序言,这本书是第二版,讲解的jdk版本是1.7,现在公司用的1.8,而且1.8的改动也挺大的,不过在 ...

  2. jdk678910新特性地址

    jdk678910新特性地址 https://blog.csdn.net/f641385712/article/details/81289401 每篇一句:每个人受到的尊重从来都不是应得的,而是赢得的 ...

  3. ERP客户关系渠管理添加和修改联系人(二十一)

    树形结构treeview 前端代码: <form id="form1" runat="server"> <div> <asp:Tr ...

  4. Nginx服务状态的监控

    https://www.cnblogs.com/beginner-boy/p/8052908.html

  5. PHP实现数据分页显示

    分页在后台管理中是经常使用的功能,分页显示方便大量数据的管理. 实例代码如下: <!DOCTYPE html> <html> <head> <meta cha ...

  6. 000 SpringMVC介绍

    1.介绍 2.MVC 模型(Model)封装了应用程序数据,通常它们将由POJO类组成. 视图(View)负责渲染模型数据,一般来说它生成客户端浏览器可以解释HTML输出. 控制器(Controlle ...

  7. node.js之nodemon 代码热更新 修改代码后服务器自动重启

    1.安装nodemon: npm install -g nodemon //全局安装 npm install nodemon --save //局部安装 2.在项目根目录下创建 nodemon.jso ...

  8. Django -- settings 详解(转)

    Django -- settings 详解   Django settings详解 1.基础 DJANGO_SETTING_MODULE环境变量:让settings模块被包含到python可以找到的目 ...

  9. 【Ray Tracing in One Weekend 超详解】 光线追踪1-3

    学完了插值,我们来学习在场景里面添加一个立体彩色球(三维插值) 按照惯例,先看效果: Chapter4: Adding a sphere 我们又一次面临图形学的主要任务. 我们需要再次回顾coord1 ...

  10. Java变量的默认值和初始化

    Java变量的默认值和初始化 学习自 <Thinking In Java> 技术小黑屋-为什么局部变量需要显式设置初始化值 变量的默认值 注意只有成员变量才有默认值,而局部变量必须要赋初值 ...