本随笔续接:.NET 实现并行的几种方式(一)

四、Task

3)Task.NET 4.5 中的简易方式

在上篇随笔中,两个Demo使用的是 .NET 4.0 中的方式,代码写起来略显麻烦,这不 .NET 4.5提供了更加简洁的方式,让我们来看一下吧。

        /// <summary>/// Task.NET 4.5 中的简易方式/// </summary>public void Demo3(){Task.Run(() =>{SetTip("简洁的代码");});Task.Run(() =>{SetTip("验证 CreationOptions 属性");}).ContinueWith((t)=> {SetTip("CreationOptions:" + t.CreationOptions.ToString());                });}

五、TPL (Task Parallel Library)

TPL (任务并行库)是 .NET 4.0 中的另一个重量级模块,可以极其优雅、便捷地完成并行逻辑的编码工作。

1)Parallel.Invoke并行多个独立的Action

        /// <summary>/// Parallel.Invoke并行多个独立的Action/// </summary>public void Demo1(){Task.Run(() =>{List<Action> actions = new List<Action>();// 生成并行任务for (int i = 0; i < 5; i++){// 注意、这里很关键,不可直接使用i变量。 // 原因在稍后的随笔中进行说明int index = i;actions.Add(new Action(() =>{SetTip(string.Format("Task{0} 开始", index));SetTip(string.Format("Task{0} 休眠1秒", index));Thread.Sleep(1000);SetTip(string.Format("Task{0} 休眠5秒", index));Thread.Sleep(5000);SetTip(string.Format("Task{0} 结束", index));}));}// 执行并行任务Parallel.Invoke(actions.ToArray());// 当上述的5个任务全部执行完毕后,才会执行该代码SetTip("并行任务执行完毕");});}

2)Parallel简单的For并行

如果 Parallel.Invoke 看做是任务并行, 则 Parallel.For 则是数据并行,可方便的完成For循环并行遍历。

        /// <summary>/// Parallel简单的For并行/// </summary>public void Demo2(){// 为了实时更新UI、将代码异步执行Task.Run(() =>{Parallel.For(1, 100, (index) =>{SetTip(string.Format("Index:{0}, 开始执行Task", index));Thread.Sleep(1000);SetTip(string.Format("Index:{0}, 开始休眠Action 1秒", index));SetTip(string.Format("Index:{0}, Task执行完毕", index));});SetTip("并行任务执行完毕");});}

3)Parallel.For并行 并行中的 break、 return、 continue

break : 在 Parallel.For 中使用 ParallelLoopState.Break() 方法代替。

return: 在 Parallel.For 中使用 ParallelLoopState.Break() 方法代替。

continue : 在 Parallel.For 中直接使用 return 即可。

        /// <summary>/// 中断Parallel.For并行/// </summary>public void Demo3(){// 为了实时更新UI、将代码异步执行Task.Run(() =>{int breakIndex = new Random().Next(10, 50);SetTip(" BreakIndex : -------------------------" + breakIndex);Parallel.For(1, 100, (index, state) =>{SetTip(string.Format("Index:{0}, 开始执行Task", index));if (breakIndex == index){SetTip(string.Format("Index:{0}, ------------------ Break Task", index));state.Break();// Break方法执行后、// 大于 当前索引的并且未被安排执行的迭代将被放弃// 小于 当前索引的的迭代将继续正常执行直至迭代执行完毕return;}Thread.Sleep(1000);SetTip(string.Format("Index:{0}, 休眠Action 1秒", index));SetTip(string.Format("Index:{0}, Task执行完毕", index));});SetTip("并行任务执行完毕");});}/// <summary>/// 终止Parallel.For并行/// </summary>public void Demo4(){// 为了实时更新UI、将代码异步执行Task.Run(() =>{int stopIndex = new Random().Next(10, 50);SetTip(" StopIndex : -------------------------" + stopIndex);Parallel.For(1, 100, (index, state) =>{SetTip(string.Format("Index:{0}, 开始执行Task", index));if (stopIndex == index){SetTip(string.Format("Index:{0}, ------------------ Stop Task", index));state.Stop();// Stop方法执行后// 整个迭代将被放弃return;}Thread.Sleep(1000);SetTip(string.Format("Index:{0}, 休眠Action 1秒", index));SetTip(string.Format("Index:{0}, Task执行完毕", index));});SetTip("并行任务执行完毕");});}

4)Parallel.For并行中的数据聚合

在并行中,绝大多数委托都是在不同的线程中运行的,如果需要在并行中进行的数据共享、则需要考虑线程同步问题,然而线程同步会影响并行性能。

为了解决特定情况下的数据共享,而又不会因为线程同步而影响性能,Parallel.For 提供了解决方案:

        /// <summary>/// Parallel.For并行中的数据聚合/// </summary>public void Demo5(){Task.Run(() =>{// 求 1 到 10 的阶乘的 和long total = 0;Parallel.For<long>(1, 10,() =>{SetTip("LocalInit");return 0;},(index, state, local) =>{SetTip("Body");int result = 1;for (int i = 2; i < index; i++){result *= i;}local += result;return local;},(x) =>{SetTip("LocalFinally");Interlocked.Add(ref total, x);});SetTip("Total : " + total);SetTip("并行任务执行完毕");});}

MSDN备注:
对于参与循环执行的每个线程调用 LocalInit 委托一次,并返回每个线程的初始本地状态。 
这些初始状态传递到每个线程上的第一个 body 调用。 然后,每个后续正文调用返回可能修改过的状态值,传递到下一个正文调用。 
最后,每个线程上的最后正文调用返回传递给 LocalFinally 委托的状态值。 
每个线程调用 localFinally 委托一次,以对每个线程的本地状态执行最终操作。 
此委托可以被多个线程同步调用;因此您必须同步对任何共享变量的访问。

也就是说:
1) 并行中开辟的线程数 决定了 LocalInit、LocalFinally 的调用次数
2) 多个 迭代委托、Body 可能被同一个线程调用。
3) 迭代委托、Body 中的 local值,并不一定是 LocalInit 的初始值,也有可能是被修改的返回值。
4) LocalFinally 可能是被同时调用的,需要注意线程同步问题。

5)Parallel.ForEach并行

Parallel.ForEach算是另一种数据并行方式, 它与大家熟知的 IEnumerable<TSource> 接口结合十分紧密,是 foreach的并行版本。

        /// <summary>/// Parallel.ForEach并行/// </summary>public void Demo6(){Task.Run(() =>{Parallel.ForEach<int>(Enumerable.Range(1, 10), (num) =>{SetTip("Task 开始");SetTip("Task 休眠" + num + "秒");Thread.Sleep(TimeSpan.FromSeconds(num));SetTip("Task 结束");});SetTip("并行任务执行完毕");});}

6)Parallel.ForEach中的索引,中断、终止操作

在 Parallel.ForEach 中也可以轻易的获得其遍历的索引

        /// <summary>/// Parallel.ForEach中的索引,中断、终止操作/// </summary>public void Demo7(){Task.Run(() =>{Parallel.ForEach<int>(Enumerable.Range(0, 10), (num, state, index) =>{// num, 并行数据源中的数据项// state, SetTip(" Index : " + index + "         Num: " + num);});SetTip("并行任务执行完毕");});}

本随笔到此、暂告一段落。

附,Demo : http://files.cnblogs.com/files/08shiyan/ParallelDemo.zip

.NET 实现并行的几种方式(二)相关推荐

  1. java并行任务,Java 并发编程学习(五):批量并行执行任务的两种方式

    Java 并发编程学习(五):批量并行执行任务的两种方式 背景介绍 有时候我们需要执行一批相似的任务,并且要求这些任务能够并行执行.通常,我们的需求会分为两种情况: 并行执行一批任务,等待耗时最长的任 ...

  2. .NET 实现并行的几种方式(一)

    好久没有更新了,今天来一篇,算是<同步与异步>系列的开篇吧,加油,坚持下去(PS:越来越懒了). 一.Thread 利用Thread 可以直接创建和控制线程,在我的认知里它是最古老的技术了 ...

  3. 多线程基础-实现多线程的两种方式(二)

    实现多线程的两种方式: 1.实现Runnable public interface Runnable {public abstract void run(); }// RunnableTest.jav ...

  4. SpringBoot中使用AMQ的两种方式二(Java配置、注解方式)

    使用@JmsListener注解方式 1. 工程目录 2. 引入依赖 <?xml version="1.0" encoding="UTF-8"?> ...

  5. .NET 实现并行的几种方式(三)

    在前两篇随笔中,先后介绍了 Thread .ThreadPool .IAsyncResult (即 APM系列) .Task  .TPL (Task Parallel Library). 写到这些笔者 ...

  6. python 参数传递的两种方式二 名称传递

    代码如下: def fact(n,m):s=1for i in range(1,n+1):s*=ireturn s//m a=fact(n=10,m=5) print(a) 运行结果:

  7. Android获取屏幕信息的几种方式

    方式一 //获取屏幕信息的几种方式一:DisplayMetrics metrics = new DisplayMetrics();WindowManager manager = (WindowMana ...

  8. ajax上传多文件和数据,Ajax上传数据和上传文件(三种方式)

    Ajax向后端发送数据可以有三种方式:原生Ajax方式,jQuery Ajax方式,iframe+form 方式(伪造Ajax方式) Title .btn { background-color: co ...

  9. MySQL启动与关闭的3种方式

    MySQL启动与关闭的3种方式 在这里大概记述一下MySQL最常用的3种启动与关闭的方式 文章目录 MySQL启动与关闭的3种方式 一.第一种方式 二.第二种方式 三.第三种方式 总结 一.第一种方式 ...

最新文章

  1. 设计模式:模板方法(Template Method Pattern)
  2. 统一指令集架构的思考
  3. ffmpeg源码实现抽取音频并保存 --C++实现
  4. linux 模块化编译,手把手教Linux驱动1-模块化编程 module
  5. 通向架构师的道路(第一天)之Apache整合Tomcat
  6. altert/html打印出来的是[object Object]
  7. [Reverse] - 百度杯”CTF比赛 2017 二月场-CrackMe-1
  8. linux界面唤醒,Linux计算机实现自动唤醒和关闭的方法步骤详解
  9. Android数据存储——SharedPreferences
  10. 索引sql server_SQL Server索引–系列介绍
  11. android Launcher——ui框架
  12. 【记录】JS回调函数(小例子)
  13. 运用Excel实现描述性统计分析
  14. Nifi从入门到精通(一)之 数据存储
  15. 微软服务器工程师认证,微软认证的系统工程师(MCSE)
  16. 一WAN多拨(一号多拨)实验
  17. mysql:列类型之时间日期
  18. 【MATLAB教程案例26】图像特征点提取算法matlab仿真与分析——sift,surf,kaze,corner,BRISK等
  19. python毕业设计 基于django框架个人博客系统毕业设计设计与实现
  20. QML QtLocation地图应用学习-2:实现测距功能

热门文章

  1. 移动混合开发之android文件管理新建文件和删除文件
  2. 爬虫入门-3.初识BeautifulSoup
  3. 牛客小白月赛11 Rinne Loves Xor
  4. NumPy数组创建例程
  5. Wireshark抓包分析TCP建立/释放链接的过程以及状态变迁分析
  6. win10配置JAVA和tomacat环境变量
  7. getDate()返回日期不一致问题引发的bug
  8. charles抓包工具使用指南
  9. Python用subprocess的Popen来调用系统命令
  10. Jetty 服务器架构分析(中)