C#并发编程-3 并行编程基础
如果程序中有大量的计算任务,并且这些任务能分割成几个互相独立的任务块,那就应该使用并行编程。
并行编程用于分解计算密集型的任务片段,并将它们分配给多个线程。这些并行处理方法只适用于计算密集型的任务。
一 数据的并行处理
如果有一批数据,需要对每个数据进行相同的操作,其操作是计算密集型的,需要耗费一定的时间。
Parallel 类型有 ForEach 方法可以解决上述问题。
下例使用了一批矩阵,对每一个矩阵都进行旋转,Matrix类的Rotate方法是计算密集型的任务。
void RotateMatrices(IEnumerable<Matrix> matrices, float degrees)
{
Parallel.ForEach(matrices, matrix => matrix.Rotate(degrees));
}
在某些情况下需要尽早结束这个循环,例如发现了无效值时。下例反转每一个矩阵,但是如果发现有无效的矩阵,则中断循环:
void InvertMatrices(IEnumerable<Matrix> matrices)
{
Parallel.ForEach(matrices, (matrix, state) =>
{
if (!matrix.IsInvertible)
state.Stop();
else
matrix.Invert();
});
}
更常见的情况是可以取消并行循环,这与结束循环不同。结束(stop)循环是在循环内部进行,
而取消(cancel)循环是在循环外部进行的。例如,点击“取消”按钮可以取消一个 CancellationTokenSource,以取消并行循环,如下:
void RotateMatrices(IEnumerable<Matrix> matrices, float degrees,CancellationToken token)
{
Parallel.ForEach(matrices,new ParallelOptions { CancellationToken = token }, matrix => matrix.Rotate(degrees));
}
注意,每个并行任务可能都在不同的线程中运行,因此必须保护对共享的状态。
二 并行聚合
Parallel 类通过局部值(local value)的概念来实现聚合,局部值就是只在并行循环内部存在的变量。
这意味着循环体中的代码可以直接访问值,不需要担心同步问题。
循环中的代码使用 LocalFinally 委托来对每个局部值进行聚合。
需要注意的是,localFinally 委托需要以同步的方式对存放结果的变量进行访问。
下面是一个并行求累加和的例子:
//注意,这不是最高效的实现方式,只是举个例子,说明用锁来保护共享状态。
static int ParallelSum(IEnumerable<int> values)
{
object mutex = new object();
int result = 0;
Parallel.ForEach(
source: values,
localInit: () => 0,
body: (item, state, localValue) => localValue + item,
localFinally: localValue =>
{
lock (mutex)
result += localValue;
}
);
return result;
}
并行 LINQ 对聚合的支持,比 Parallel 类更加易用:
static int ParallelSum(IEnumerable<int> values)
{
return values.AsParallel().Sum();
}
PLINQ 本身支持很多常规操作(例如求累加和)。大多数情况下PLINQ 对聚合的支持更有表现力,代码也更少。
PLINQ也可通过 Aggregate 实现通用的聚合功能:
static int ParallelSum(IEnumerable<int> values)
{
return values.AsParallel().Aggregate(
seed: 0,
func: (sum, item) => sum + item
);
}
三 并行调用
如果需要并行调用一批方法,并且这些方法(大部分)是互相独立的。
下面的例子将一个数组分为两半,并且分别独立处理:
static void ProcessArray(double[] array)
{
Parallel.Invoke(
() => ProcessPartialArray(array, 0, array.Length / 2),
() => ProcessPartialArray(array, array.Length / 2, array.Length)
);
}
static void ProcessPartialArray(double[] array, int begin, int end)
{
// 计算密集型的处理过程 ...
}
如果在运行之前都无法确定调用的方法数量,就可以在 Parallel.Invoke 函数中输入一个委托数组,Parallel.Invoke 也支持取消操作:
static void DoAction20Times(Action action, CancellationToken token)
{
Action[] actions = Enumerable.Repeat(action, 20).ToArray();
Parallel.Invoke(new ParallelOptions { CancellationToken = token }, actions);
}
对于简单的并行调用,Parallel.Invoke 是一个非常不错的解决方案。
但在以下两种情况中使用 Parallel.Invoke 并不是很合适:
要对每一个输入的数据调用一个操作(改用Parallel.Foreach),或者每一个操作产生了一些输出(改用并行 LINQ)。
四 并行LINQ
LINQ 可以实现在序列上”拉取“数据的运算。并行LINQ(PLINQ)扩展了 LINQ,以支持并行处理。
PLINQ 非常适用于数据流的操作,一个数据队列作为输入,一个数据队列作为输出。
下面简单的例子将序列中的每个元素都乘以2:
static IEnumerable<int> MultiplyBy2(IEnumerable<int> values)
{
return values.AsParallel().Select(item => item * 2); //实际应用中,计算工作量要大得多
}
按照并行 LINQ 的默认方式,这个例子中输出数据队列的次序是不固定的。
我们可以指明要求保持原来的次序。下面的例子也是并行执行的,但保留了数据的原有次序:
static IEnumerable<int> MultiplyBy2(IEnumerable<int> values)
{
return values.AsParallel().AsOrdered().Select(item => item * 2);
}
Parallel 类可适用于很多场合,但是在做聚合或进行数据序列的转换时,PLINQ 的代码更加简洁。
PLINQ 为各种各样的操作提供了并行的版本,包括过滤(Where)、投影(Select)以及各种聚合运算,
例如 Sum、Average 和更通用的 Aggregate。一般来说,对常规 LINQ 的所有操作都可以通过并行方式对 PLINQ 执行。
以上。
C#并发编程-3 并行编程基础的更多相关文章
- C#并行编程-并发集合
菜鸟学习并行编程,参考<C#并行编程高级教程.PDF>,如有错误,欢迎指正. 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 ...
- C#并行编程中的Parallel.Invoke
一.基础知识 并行编程:并行编程是指软件开发的代码,它能在同一时间执行多个计算任务,提高执行效率和性能一种编程方式,属于多线程编程范畴.所以我们在设计过程中一般会将很多任务划分成若干个互相独立子任务, ...
- C#并行编程
C#并行编程中的Parallel.Invoke 一.基础知识 并行编程:并行编程是指软件开发的代码,它能在同一时间执行多个计算任务,提高执行效率和性能一种编程方式,属于多线程编程范畴.所以我们在设计过 ...
- 并行编程(Parallel Framework)
前言 并行编程:通过编码方式利用多核或多处理器称为并行编程,多线程概念的一个子集. 并行处理:把正在执行的大量的任务分割成小块,分配给多个同时运行的线程.多线程的一种. 并行编程分为如下几个结构: 1 ...
- C#并行编程系列-文章导航
菜鸟初步学习,不对的地方请大神指教,参考<C#并行编程高级教程.pdf> 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 C# ...
- C#并行编程-相关概念
菜鸟初步学习,不对的地方请大神指教,参考<C#并行编程高级教程.pdf> 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 C# ...
- C#并行编程-Parallel
菜鸟学习并行编程,参考<C#并行编程高级教程.PDF>,如有错误,欢迎指正. 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 ...
- C#并行编程-Task
菜鸟学习并行编程,参考<C#并行编程高级教程.PDF>,如有错误,欢迎指正. 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 ...
- C#并行编程-线程同步原语
菜鸟学习并行编程,参考<C#并行编程高级教程.PDF>,如有错误,欢迎指正. 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 ...
随机推荐
- Hive优化(面试宝典)(详细的九个优化)
Hive优化(面试宝典) 1.1 hive的随机抓取策略 理论上来说,Hive中的所有sql都需要进行mapreduce,但是hive的抓取策略帮我们 省略掉了这个过程,把切片split的过程提前帮我 ...
- java 桥接方法
1.桥接方法简介 桥接方法是jdk1.5引入泛型后,为使java泛型方法生成的字节码与jdk1.5版本之前的字节码兼容由编译器自动生成的. 可用method.isBridge() 判断method是否 ...
- IDEA自定义liveTemplates(方法模板、类模板)
IDEA自定义liveTemplates(方法模板.类模板) 前言,搞这个模板有何意义? 降低大家写方法注释的成本,统一风格.有时候不是开发同学不爱写注释,而是没有合适的载体和空间. IDEA模板设置 ...
- 1000-ms-maven相关问题
一.Maven有哪些优点和缺点 优点如下: 简化了项目依赖管理: 易于上手,对于新手可能一个"mvn clean package"命令就可能满足他的工作 便于与持续集成工具(jen ...
- Vs 快捷键---探索不一样的编程
前言:现在很多工具都支持各式各样的快捷键,vs作为后起之秀,多功能的快捷键自然是必不可少的, 而且针对单行操作的快捷键是无需选中整行的,只需要光标停留在所操作的代码上面即可. 1.注释:CTRL+K+ ...
- 密码学系列之:PEM和PKCS7,PKCS8,PKCS12
目录 简介 PEM PKCS7 PKCS8 PKCS12 总结 简介 PEM是一种常见的保存key或者证书的格式,PEM格式的文件一般来说后缀是以.pem结尾的.那么PEM到底是什么呢?它和常用的证书 ...
- MySQL Update执行流程解读
GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 一.update跟踪执行配置 使用内部程序堆栈跟踪工具path_viewer,跟踪mysql update 一行数据的执行 ...
- Linux 07 用户组文件
参考源 https://www.bilibili.com/video/BV187411y7hF?spm_id_from=333.999.0.0 版本 本文章基于 CentOS 7.6 概述 用户组的所 ...
- 在.NET 6.0中使用不同的托管模型
大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进. 本章是<定制ASP NET 6.0框架系列文章>的第六篇.在本章中,我 ...
- java学习第三天常用类.day11
工具类如何设计,在开发中有两种设计: 工具方法:静态方法的使用 非静态的方法使用: 使用单列模式,为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 保证在整个应用中某一个类有且只有一个实例(一 ...