C#编程(六十四)----------并行扩展
并行的扩展
扩展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#编程(六十四)----------并行扩展的更多相关文章
- Gradle 1.12用户指南翻译——第六十四章. 发布到Ivy(新)
其他章节的翻译请参见:http://blog.csdn.net/column/details/gradle-translation.html翻译项目请关注Github上的地址:https://gith ...
- 孤荷凌寒自学python第六十四天学习mongoDB的基本操作并进行简单封装3
孤荷凌寒自学python第六十四天学习mongoDB的基本操作并进行简单封装3 (完整学习过程屏幕记录视频地址在文末) 今天是学习mongoDB数据库的第十天. 今天继续学习mongoDB的简单操作, ...
- SpringBoot进阶教程(六十四)注解大全
在Spring1.x时代,还没出现注解,需要大量xml配置文件并在内部编写大量bean标签.Java5推出新特性annotation,为spring的更新奠定了基础.从Spring 2.X开始spri ...
- 第三百六十四节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的mapping映射管理
第三百六十四节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的mapping映射管理 1.映射(mapping)介绍 映射:创建索引的时候,可以预先定义字 ...
- “全栈2019”Java第六十四章:接口与静态方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- 学习ASP.NET Core Razor 编程系列十四——文件上传功能(二)
学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...
- OpenCV开发笔记(六十四):红胖子8分钟带你深入了解SURF特征点(图文并茂+浅显易懂+程序源码)
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- C#高级编程六十九天----DLR简介 .在.NET中使用DLR(转载) 我也来说说Dynamic
DLR 一.近年来,在TIOBE公司每个月发布的编程语言排行榜中,C#总是能挤进前十名,而在最近十年来,C#总体上呈现上升的趋势.C#能取得这样的成绩,有很多因素,其中它在语言特性上的锐意进取让人印象 ...
- 第六十四天 JS基础操作
一.分支结构 1.if语句 if基础语句 if(条件表达式){ 代码块: } // 当条件表达式结果为true,会执行代码块:反之不执行 // 条件表达式可以为普通表达式 // 0.undefined ...
随机推荐
- 三、vue脚手架工具vue-cli的使用
1.vue-cli构建 vue-cli工具构建:https://blog.csdn.net/u013182762/article/details/53021374 npm的镜像替换成淘宝 2.项目运行 ...
- 从零开始自己搭建复杂网络(以Tensorflow为例)
从零开始自己搭建复杂网络(以MobileNetV2为例) tensorflow经过这几年的发展,已经成长为最大的神经网络框架.而mobileNetV2在经过Xception的实践与深度可分离卷积的应用 ...
- MCS-51 单片机的中断系统
MCS-51 单片机的中断系统 MCS-51中断系统:5个中断源(两个外部中断, 两个定时器, 一个串口),2个优先级 中断相关概念 中断:当CPU正在处理某件事情时,单片机外部或内部发生的某一紧急事 ...
- NOIp 2018 提高组
T1铺设道路 传送门 题目描述 春春是一名道路工程师,负责铺设一条长度为 $ n $ 的道路. 铺设道路的主要工作是填平下陷的地表.整段道路可以看作是 $ n $ 块首尾相连的区域,一开始,第 ii ...
- 当父级绑定了DataContext之内的数据源时,子级想重新绑回DataContext
<Grid x:Name="NewDeploymentObjectPanel" Background="White" DataContext=" ...
- 如何批量删除word文档中的超级链接?
有时候从网页上copy来的文章中,会带有非常多的链接,这些链接很烦人是吧?如何批量删除(一次性全部删除)word文章中的超链接呢? 有些朋友说,Ctrl+A全选文章,然后点击格式工具栏上的“清除格式” ...
- 《Look Mom, I don’t use Shellcode》议题解析
0x0 前言 <Look Mom, I don’t use Shellcode>是2016年Syscan360上讲过的一个议题,这个议题的副标题是"Browser Exploit ...
- 《高性能MySQL》学习笔记
第1章 MySQL架构与历史 1.2 并发控制 MySQL在两个层面实现并发控制:服务器层与存储引擎层. 读锁和写锁: 在处理并发读或写时,可以通过实现一个由两种锁组成的系统来解决问题. 这两种锁通常 ...
- jquery.validate.js自定义表单验证
$(document).ready(function() { //在下列位置输入页面加载的逻辑代码 $("#inputForm").validate({ rules: { seq: ...
- js冲刺一下
js中__proto__和prototype的区别和关系 1.对象有属性__proto__,指向该对象的构造函数的原型对象. 2.方法除了有属性__proto__,还有属性prototype,prot ...