本随笔续接:.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());
});
}

Task.NET 4.5 中的简易方式

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

Parallel.Invoke并行多个独立的Action

2)Parallel简单的For并行

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

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

Parallel简单的For并行

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(, );
SetTip(" BreakIndex : -------------------------" + breakIndex); Parallel.For(, , (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();
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(, );
SetTip(" StopIndex : -------------------------" + stopIndex); Parallel.For(, , (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();
SetTip(string.Format("Index:{0}, 休眠Action 1秒", index)); SetTip(string.Format("Index:{0}, Task执行完毕", index));
}); SetTip("并行任务执行完毕");
});
}

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

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

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

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

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

Parallel.For并行中的数据聚合

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(, ), (num) =>
{
SetTip("Task 开始"); SetTip("Task 休眠" + num + "秒");
Thread.Sleep(TimeSpan.FromSeconds(num)); SetTip("Task 结束");
}); SetTip("并行任务执行完毕");
});
}

Parallel.ForEach并行

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

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

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

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

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

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

参见更多:随笔导读:同步与异步

(未完待续...)

.NET 实现并行的几种方式(二)的更多相关文章

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

    本随笔续接:.NET 实现并行的几种方式(二) 在前两篇随笔中,先后介绍了 Thread .ThreadPool .IAsyncResult (即 APM系列) .Task .TPL (Task Pa ...

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

    本随笔续接:.NET 实现并行的几种方式(三) 八.await.async - 异步方法的秘密武器 1) 使用async修饰符 和 await运算符 轻易实现异步方法 前三篇随笔已经介绍了多种方式.利 ...

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

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

  4. iOS开发 - OC - 实现本地数据存储的几种方式二(直接使用sqlite)

    连接上一篇文章http://www.cnblogs.com/FBiOSBlog/p/5819418.html. 上一篇文章介绍了OC内部一些方法进行数据的本地存储,其中包括 NSUser类.Plist ...

  5. python缓存装饰器,第二种方式(二)

    来个简单的装饰器 def cached_method_result(fun): """方法的结果缓存装饰器""" @wraps(fun) d ...

  6. Django文件上传三种方式以及简单预览功能

    主要内容: 一.文件长传的三种方式 二.简单预览功能实现 一.form表单上传 1.页面代码 <!DOCTYPE html> <html lang="en"> ...

  7. 软件调用QML的两种方式

    一.两种方式 二.方式1[对窗口的控制权在QML] 三.方式2[对窗口的控制权在C++]

  8. Spring创建JobDetail的两种方式

    一.Spring创建JobDetail的两种方式 二.整合方式一示例步骤 1.将spring核心jar包.quartz.jar和Spring-context-support.jar导入类路径. 2.编 ...

  9. 加载映射文件几种方式和mapper接口注解执行sql语句

    一.加载映射文件几种方式 二.mapper接口注解执行sql语句 就将xml中的sql语句放到注解的括号中就可以,一般只用于简单的sql语句合适:

随机推荐

  1. 基于SignalR实现B/S系统对windows服务运行状态的监测

    通常来讲一个BS项目肯定不止单独的一个BS应用,可能涉及到很多后台服务来支持BS的运行,特别是针对耗时较长的某些任务来说,Windows服务肯定是必不可少的,我们还需要利用B/S与windows服务进 ...

  2. SDWebImage源码解读 之 NSData+ImageContentType

    第一篇 前言 从今天开始,我将开启一段源码解读的旅途了.在这里先暂时不透露具体解读的源码到底是哪些?因为也可能随着解读的进行会更改计划.但能够肯定的是,这一系列之中肯定会有Swift版本的代码. 说说 ...

  3. JS继承之寄生类继承

    原型式继承 其原理就是借助原型,可以基于已有的对象创建新对象.节省了创建自定义类型这一步(虽然觉得这样没什么意义). 模型 function object(o){ function W(){ } W. ...

  4. Axure 8.0.0.3312可用注册码

    用户名:aaa 注册码:2GQrt5XHYY7SBK/4b22Gm4Dh8alaR0/0k3gEN5h7FkVPIn8oG3uphlOeytIajxGU 用户名:axureuser 序列号:8wFfI ...

  5. Android:Activity+Fragment及它们之间的数据交换.

    Android:Activity+Fragment及它们之间的数据交换 关于Fragment与Fragment.Activity通信的四种方式 比较好一点的Activity+Fragment及它们之间 ...

  6. Activity之概览屏幕(Overview Screen)

    概览屏幕 概览屏幕(也称为最新动态屏幕.最近任务列表或最近使用的应用)是一个系统级别 UI,其中列出了最近访问过的 Activity 和任务. 用户可以浏览该列表并选择要恢复的任务,也可以通过滑动清除 ...

  7. GSD_WeiXin(高仿微信)应用源码

    高仿微信计划:已经实现功能 1.微信首页(cell侧滑编辑.下拉眼睛动画.下拉拍短视频.点击进入聊天详情界面) 2.通讯录(联系人字母排序.搜索界面) 3.发现(朋友圈) 4.我(界面) 待实现功能( ...

  8. Ajax.BeginForm方法 参数

    感谢博主 http://www.cnblogs.com/zzgblog/p/5454019.html toyoung 在Asp.Net的MVC中的语法,在Razor页面中使用,替代JQuery的Aja ...

  9. Centos6.5 配置Nginx开机自启动

    1.在/etc/init.d/目录下创建 nginx 文件,内容如下: #!/bin/sh # # nginx - this script starts and stops the nginx dae ...

  10. FineReport关于tomcat集群部署的方案

    多台服务器集群后,配置权限.数据连接.模板.定时调度等,只能每台服务器一个个配置,不会自动同步到所有服务器. 针对上述情况,在FineReport中提供新集群部署插件,将xml配置文件.finedb/ ...