在C#中使用多线程的一个示例
问题描述:
在最近的一个项目中,有一段代码逻辑是对一个数组中的所有元素调用相同的处理函数,并返回结果,且这个处理函数耗时比较久,典型的可以并行化处理的例子。
解决思路:
上述问题,可以简化成如何并行执行map
函数或者并行执行foreach
函数,幸运的是,在.Net 4.0中,这两个函数都有并行版本,分别是PLINQ和Parallel.ForEach。
解决细节:
并行化的
map
在C#中,是没有函数式编程中的
map
、reduce
、filter
等函数,但这几个函数都可以通过LINQ来做到,对应关系是map <-> Select
、reduce <-> Aggregate
、filter <-> Where
。并且,LINQ支持链式操作,再加上C#也支持匿名函数,写起来非常清爽干净。比如,需要计算班里所有男生成绩的总和,只需要1
var scoreSum = students.Select(stu => stu.score).Where(stu => stu.gender == "male").Aggregate((sum, next) => sum + next);
更酷的是,在链式调用中,加上
.AsParallel()
,整个操作过程就变成并行版本了,也就是前面说到的PLINQ。并行化的
ForEach
Parallel.ForEach
是ForEach
的并行版,调用规则也非常简单。例如,打印班里所有男生的成绩,使用Parallel.ForEach
实现如下:1
2
3
4
5
6
7Parallel.ForEach(students, stu =>
{
if (stu.gender == "male")
{
Console.WriteLine(stu.score);
}
});比较
关于这两种并行解决方案到底需用哪个,这里有篇文章详细对比了这两种解决方案的适用场景。我自己使用PLINQ来实现,仅用一行代码就解决了我的问题,形式如下:
1
var result = list.AsParallel().AsOrdered().Select(x => DoSomething(x)).ToList();
其中特别要注意的是,加上
.AsOrdered()
保证返回结果中result与输入list中的值是一一对应的。