5天玩转C#并行和多线程编程
5天玩转C#并行和多线程编程系列文章目录
5天玩转C#并行和多线程编程 —— 第一天 认识Parallel
5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq
5天玩转C#并行和多线程编程 —— 第三天 认识和使用Task
5天玩转C#并行和多线程编程 —— 第五天 多线程编程大总结
随着多核时代的到来,并行开发越来越展示出它的强大威力!使用并行程序,充分的利用系统资源,提高程序的性能。在.net 4.0中,微软给我们提供了一个新的命名空间:System.Threading.Tasks。这里面有很多关于并行开发的东西,今天第一篇就介绍下最基 础,最简单的——认识和使用Parallel。
在Parallel下面有三个常用的方法invoke,For和ForEach。
1、 Parallel.Invoke
这是最简单,最简洁的将串行的代码并行化。
在这里先讲一个知识点,就是StopWatch的使用,最近有一些人说找不到StopWatch,StopWatch到底是什么东西,今天就来说明一下。
StopWatch在System.Diagnostics命名控件,要使用它就要先引用这个命名空间。
其使用方法如下:
var stopWatch = new StopWatch(); //创建一个Stopwatch实例
stopWatch.Start(); //开始计时
stopWatch.Stop(); //停止计时
stopWatch.Reset(); //重置StopWatch
stopWatch.Restart(); //重新启动被停止的StopWatch
stopWatch.ElapsedMilliseconds //获取stopWatch从开始到现在的时间差,单位是毫秒
本次用到的就这么多知识点,想了解更多关于StopWatch的,去百度一下吧,网上有很多资料。
下面进入整体,开始介绍Parallel.Invoke方法,废话不多说了,首先新建一个控制台程序,添加一个类,代码如下:

public class ParallelDemo
{
private Stopwatch stopWatch = new Stopwatch(); public void Run1()
{
Thread.Sleep(2000);
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.");
}
}

代码很简单,首先新加一个类,在类中写了两个方法,Run1和Run2,分别等待一定时间,输出一条信息,然后写了一个测试方法ParallelInvokeMethod,分别用两种方法调用Run1和Run2,然后在main方法中调用,下面来看一下运行时间如何:
大家应该能够猜到,正常调用的话应该是5秒多,而Parallel.Invoke方法调用用了只有3秒,也就是耗时最长的那个方法,可以看出方法是并行执行的,执行效率提高了很多。
2、Parallel.For
这个方法和For循环的功能相似,下面就在类中添加一个方法来测试一下吧。代码如下:

public void ParallelForMethod()
{
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."); }

写了两个循环,做了一些没有意义的事情,目的主要是为了消耗CPU时间,同理在main方法中调用,运行结果如下图:
可以看到,Parallel.For所用的时间比单纯的for快了1秒多,可见提升的性能是非常可观的。那么,是不是Parallel.For在任何时候都比for要快呢?答案当然是“不是”,要不然微软还留着for干嘛?
下面修改一下代码,添加一个全局变量num,代码如下:

public void ParallelForMethod()
{
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."); }

Parallel.For由于是并行运行的,所以会同时访问全局变量num,为了得到正确的结果,要使用lock,此时来看看运行结果:
是不是大吃一惊啊?Parallel.For竟然用了15秒多,而for跟之前的差不多。这主要是由于并行同时访问全局变量,会出现资源争夺,大多数时间消耗在了资源等待上面。
一直说并行,那么从哪里可以看出来Parallel.For是并行执行的呢?下面来写个测试代码:
Parallel.For(0, 100, i =>
{
Console.Write(i + "\t");
});
从0输出到99,运行后会发现输出的顺序不对,用for顺序肯定是对的,并行同时执行,所以会出现输出顺序不同的情况。
2、Parallel.Foreach
这个方法跟Foreach方法很相似,想具体了解的,可以百度些资料看看,这里就不多说了,下面给出其使用方法:
List<int> list = new List<int>();
list.Add(0);
Parallel.ForEach(list, item =>
{
DoWork(item);
});
1、当我们使用到Parallel,必然是处理一些比较耗时的操作,当然也很耗CPU和内存,如果我们中途向停止,怎么办呢?
在串行代码中我们break一下就搞定了,但是并行就不是这么简单了,不过没关系,在并行循环的委托参数中提供了一个ParallelLoopState,
该实例提供了Break和Stop方法来帮我们实现。
Break: 当然这个是通知并行计算尽快的退出循环,比如并行计算正在迭代100,那么break后程序还会迭代所有小于100的。
Stop:这个就不一样了,比如正在迭代100突然遇到stop,那它啥也不管了,直接退出。
下面来写一段代码测试一下:

public void ParallelBreak()
{
ConcurrentBag<int> bag = new ConcurrentBag<int>();
stopWatch.Start();
Parallel.For(0, 1000, (i, state) =>
{
if (bag.Count == 300)
{
state.Stop();
return;
}
bag.Add(i);
});
stopWatch.Stop();
Console.WriteLine("Bag count is " + bag.Count + ", " + stopWatch.ElapsedMilliseconds);
}

这里使用的是Stop,当数量达到300个时,会立刻停止;可以看到结果"Bag count is 300",如果用break,可能结果是300多个或者300个,大家可以测试一下。
2、异常处理
首先任务是并行计算的,处理过程中可能会产生n多的异常,那么如何来获取到这些异常呢?普通的Exception并不能获取到异常,然而为并行诞生的AggregateExcepation就可以获取到一组异常。
这里我们修改Parallel.Invoke的代码,修改后代码如下:

public class ParallelDemo
{
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.");
}
}

顺序调用方法我把异常处理写一起了,这样只能捕获Run1的异常信息,大家可以分开写。捕获AggregateException 异常后,用foreach循环遍历输出异常信息,可以看到两个异常信息都显示了。
5天玩转C#并行和多线程编程的更多相关文章
- 5天玩转C#并行和多线程编程 —— 第五天 多线程编程大总结
5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...
- 5天玩转C#并行和多线程编程 —— 第四天 Task进阶
5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...
- 5天玩转C#并行和多线程编程 —— 第三天 认识和使用Task
5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...
- 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq
5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...
- 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel
5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...
- 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 转载 https://www.cnblogs.com/yunfeifei/p/3993401.html
5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编 ...
- C#并行和多线程编程
5天玩转C#并行和多线程编程 —— 第二天 并行集合和PLinq 5天玩转C#并行和多线程编程系列文章目录 5天玩转C#并行和多线程编程 —— 第一天 认识Parallel 5天玩转C#并行和多线 ...
- C#并行和多线程编程_(1)认识Parallel
Parallel: 英 [ˈpærəlel] 美 [ˈpærəˌlɛl] ,并联的,并行的. 随着多核时代的到来,并行开发越来越展示出它的强大威力!使用并行程序,充分的利用系统资源,提高程序的性 ...
- python 常见错误和异常 函数 正则表达式及多线程编程
生成随机密码#!/usr/bin/env python import stringfrom random import choice def gen_pass(num=9): all_chs = st ...
随机推荐
- 使用新版Android Studio检测内存泄露和性能
内存泄露,是Android开发者最头疼的事.可能一处小小的内存泄露,都可能是毁于千里之堤的蚁穴. 怎么才能检测内存泄露呢?网上教程非常多,不过很多都是使用Eclipse检测的, 其实1.3版本以后的 ...
- Filestream(读写)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.I ...
- Hbase写入hdfs源码分析
版权声明:本文由熊训德原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/258 来源:腾云阁 https://www.qclo ...
- 【转】 深入main函数中的参数argc,argv的使用详解
C/C++语言中的main函数,经常带有参数argc,argv,如下: 复制代码 代码如下: int main(int argc, char** argv) 这两个参数的作用是什么呢?argc 是指命 ...
- SPSS常用基础操作(3)——对数据资料进行整理
在实际工作中,往往需要对取得的数据资料进行整理,使其满足特定的分析需求,下面介绍SPSS在资料整理方面的一些功能. 1.加权个案加权个案是指给不同的个案赋予不同的权重,以改变该个案在分析中的重要性.为 ...
- Redis + php扩展的安装与配置(windows)
-->安装Redis服务 下载redis安装包 http://pan.baidu.com/s/1pJiVFHx 下载后解压 把解压后文件夹里面的文件(根据自己的系统位数选择32位或者64位)拷贝 ...
- VUE应用的一些感受
方便,数据绑定太方便了. 一个组件一个.vue文件特别清晰. 讲真vue比angular好学多了. webpack打包最近看懂,通过一个主文件把require的文件都打进来.业务代码放build里,引 ...
- 转 Android开发笔记(成长轨迹)
http://blog.csdn.net/mad1989/article/details/9142557
- QT打开ROS工作空间时遇到的问题和解决方法
之前一直觉得不用IDE写程序看着好像我很能的样子. 其实就相当于工业时代我还钻木取火并且告诉别人你们用打火机根本不知道火被点燃的过程是怎样的. 因为这个技能并非人人都会,就可以拿出去到处臭屁 好了, ...
- 完美实现跨域Iframe高度自适应【Iframe跨域高度自适应解决方案】
Iframe的强大功能偶就不多说了,它不但被开发人员经常运用,而且黑客们也常常使用它,总之用过的人知道它的强大之处,但是Iframe有个致命的“BUG”就是iframe的高度无法自动适应,这一点让很多 ...