C#并行库(TaskParallelLibrary)用法 z
1. Task.Factory.StartNew(() => DoSomeWork());是异步的
下面的代码会先输出ddd,因为Task.Factory.Startnew不阻塞:
var task = Task.Factory.StartNew(() => Console.WriteLine("eee"));
Console.WriteLine("ddd");
如果你想阻塞,应该加上wait,改为这样:
var task = Task.Factory.StartNew(() => Console.WriteLine("eee")).Wait();
Console.WriteLine("ddd");
同样,Task.Factory.StartNew(() => DoSomeWork()).ContinueWith…也是是异步的,想让它阻塞,应该加上wait,这样写:
var task = Task.Factory.StartNew(() => return "").ContinueWith( s => { Console.WriteLine(s.Result); }).Wait();
Console.WriteLine("ddd");
2. Task.Factory.StartNew(() => DoSomeWork()).ContinueWith…没有运行在新的线程里
var task = Task.Factory.StartNew(() => return "").ContinueWith( s =>
{
DoSomething2(s.Result);
}).Wait();
Console.WriteLine("ddd");
注意上面的DoSomething2()是运行在主线程,而不是在新的线程里
3. Parallel.ForEach为何导致内存溢出
如果对一个10000个item的collection使用Parallel.ForEach,可以想象会发生什么。TPL默认是 Parallel.ForEach使用场景是对CPU敏感的,TPL会持续创建线程,直到你的CPU利用率达100%;问题是你的使用场景如果不是CPU 敏感的,例如是I/O敏感的,TPL想尽可能的利用你的CPU,所以检测你的CPU利用率,如果还不是100%就会一直创建线程....直到内存耗尽。所 以,使用要注意使用场景十分CPU敏感的,另外可以加一个参数来限制TPL线程的创建:
Parallel.ForEach(items,
new ParallelOptions
{
MaxDegreeOfParallelism = 4
},
item => DoSomething(item));
ParallelOptions.MaxDegreeOfParallelism参数含义:
If your task is CPU-bound then you should see a pattern like this on a quad-core system:
ParallelOptions.MaximumDegreeOfParallelism = 1: use one full CPU or 25% CPU utilizationParallelOptions.MaximumDegreeOfParallelism = 2: use two CPUs or 50% CPU utilizationParallelOptions.MaximumDegreeOfParallelism = 4: use all CPUs or 100% CPU utilization
4. 如何等待Parallel.ForEach运行都结束
Parallel.ForEach<Item>(items, item => DoSomething(item));
Console.WriteLine("ddd");
是阻塞的,所以以上代码会在最后输出ddd。
如果是等多个Task,可以这样写:
var task1 = Task.Factory.StartNew(() => DoSomeWork());
var task2 = Task.Factory.StartNew(() => DoSomeWork());
var task3 = Task.Factory.StartNew(() => DoSomeWork());
Task.WaitAll(task1, task2, task3);
或者这样写:
Task.Factory.ContinueWhenAll(new[] { task1, task2, task3 }, tasks =>
{
foreach (Task<string> task in tasks)
{
Console.WriteLine(task.Result);
}
});
5. Task.Factory.StartNew和Parallel.ForEach可以嵌套使用吗
都可以嵌套使用,例如:
var task1 = Task.Factory.StartNew( () => Parallel.ForEach<Item>(items, item => DoSomething(item)));
var task2 = Task.Factory.StartNew( () => Parallel.ForEach<Item>(items2, item => DoSomething2(item)));
Task.WaitAll(task1, task2);
6. Thread.Sleep还需要吗
以前,我们轮询的时候常常喜欢这样的写法:
while(true)
{
doSomework();
Thread.Sleep(1000);
}
这是一种代码的坏味道,Stackoverflow的讨论在这儿,解决方法是用WaitEvent替代,当然在C#中还是推荐用BlockingCollection替代。
6. TPL中闭包的陷阱
例如在下面的代码中 counter++存在线程不安全的问题。
int counter = 0;
Task.Factory.StartNew( () =>
Parallel.ForEach(items,
new ParallelOptions
{
MaxDegreeOfParallelism = 4
},
item => {
DoSomething(item);
counter++;
});
);
应该改为:
Interlocked.Increment(ref successCount);
7. Lock锁带来的性能问题
性能问题首先要诊断,例如用条件编译打印出线程id和运行时序,可以知道所有线程的运行先后次序和等待情况。还可以借助工具来调试多线 程问题。这里要说的锁的问题。如果你的程序用Parallel.ForEach貌似是并发的,但如果有用到Lock,那可能你所有的线程都在等待,性能将 是一塌糊涂的。所以最好的方法是避免锁,保证Parallel.ForEach里面每一个对象不会用到竞争的资源/例如修改同一个对象。退而求其次的是用 锁,但要非常小心。例如,lock(this),lock(typeof(mytype)),lock(“mylock”),如果lock的是 public访问的,或者锁名字一样,将会造成问题。还有的人干脆来个大括号,一整段全都锁住。死锁有时候很难调试发现诊断,下面的代码有死锁:
// thread 1
lock(typeof(int)) {
Thread.Sleep(1000);
lock(typeof(float)) {
Console.WriteLine("Thread 1 got both locks");
}
}
// thread 2
lock(typeof(float)) {
Thread.Sleep(1000);
lock(typeof(int)) {
Console.WriteLine("Thread 2 got both locks");
}
}
8. TaskFactory.Startnew和异步async/await的不同
var Data = await Task.WhenAll(WebService1.Call(),
WebService2.Call(),
WebService3.Call());
关于TaskFactory.Startnew和异步async/await的不同,下面两文章已经讲的非常清楚了:
- http://msdn.microsoft.com/en-us/library/dd997423.aspx
- http://stackoverflow.com/questions/10285159/difference-between-the-tpl-async-await-thread-handling
在下面的情况下,推荐使用Task.Factory.FromAsync()因为异步I/O比同步的CPU等待等有效,特别是对于获取I/O的高伸缩性。
NetworkStream stream;
byte[] data;
int bytesRead;
//using FromAsync
Task<int> readChunk = Task<int>.Factory.FromAsync (
stream.BeginRead, stream.EndRead,
data, bytesRead, data.Length - bytesRead, null);
//using StartNew with blocking version
Task<int> readChunk2 = Task<int>.Factory.StartNew(() =>
stream.Read(data, bytesRead, data.Length - bytesRead));
9. 其它资源
C#并行库(TaskParallelLibrary)用法 z的更多相关文章
- C#并行库(TaskParallelLibrary)用法小结
今天有空,总结一下.NET 4.5并行库(TaskParallelLibrary)用法. 也许C和C++的程序员刚刚开始写C#还习惯于new Thread来新建一个线程,但新建线程需要内存和CPU上下 ...
- C#5.0之后推荐使用TPL(Task Parallel Libray 任务并行库) 和PLINQ(Parallel LINQ, 并行Linq). 其次是TAP(Task-based Asynchronous Pattern, 基于任务的异步模式)
学习书籍: <C#本质论> 1--C#5.0之后推荐使用TPL(Task Parallel Libray 任务并行库) 和PLINQ(Parallel LINQ, 并行Linq). 其次是 ...
- [C#]『PLINQ』任务并行库使用小计
并行 LINQ (PLINQ) 是 LINQ to Objects 的并行实现. PLINQ 实现完整的 LINQ 标准查询运算符集作为 T:System.Linq 命名空间的扩展方法,并具有用于并行 ...
- C#当中的多线程_任务并行库(上)
复习: 第三章内容中我们提到了三种异步编程模型,这里简单复习一下,分别如下 1.APM(异步编程模式):形如Beginxxx,Endxxx. 2.EAP(基于事件的异步编程模式):这个我们在.net中 ...
- Delphi XE7中新并行库
Delphi XE7中添加了新的并行库,和.NET的Task和Parellel相似度99%. 详细内容能够看以下的文章: http://www.delphifeeds.com/go/s/119574 ...
- DELPHI XE7 新的并行库
DELPHI XE7 的新功能列表里面增加了并行库System.Threading, System.SyncObjs. 为什么要增加新的并行库? 还是为了跨平台.以前要并行编程只能从TThread类继 ...
- (转)Python爬虫利器一之Requests库的用法
官方文档 以下内容大多来自于官方文档,本文进行了一些修改和总结.要了解更多可以参考 官方文档 安装 利用 pip 安装 $ pip install requests 或者利用 easy_install ...
- python爬虫---selenium库的用法
python爬虫---selenium库的用法 selenium是一个自动化测试工具,支持Firefox,Chrome等众多浏览器 在爬虫中的应用主要是用来解决JS渲染的问题. 1.使用前需要安装这个 ...
- C#多线程编程系列(五)- 使用任务并行库
目录 1.1 简介 1.2 创建任务 1.3 使用任务执行基本的操作 1.4 组合任务 1.5 将APM模式转换为任务 1.6 将EAP模式转换为任务 1.7 实现取消选项 1.8 处理任务中的异常 ...
- Python爬虫利器一之Requests库的用法
前言 之前我们用了 urllib 库,这个作为入门的工具还是不错的,对了解一些爬虫的基本理念,掌握爬虫爬取的流程有所帮助.入门之后,我们就需要学习一些更加高级的内容和工具来方便我们的爬取.那么这一节来 ...
随机推荐
- 洛谷 [TJOI2010]中位数
题目链接 题解 比较水.. 常见套路,维护两个堆 Code #include<bits/stdc++.h> #define LL long long #define RG register ...
- [转] PuTTY + Xming 远程使用 Linux GUI
[From] http://www.zw1840.com/blog/zw1840/2008/10/putty-xming-linux-gui.html By zw1840 on October 28, ...
- Oracle sql 中的 ALL,ANY,SOME
[转自] http://www.itpub.net/thread-1355835-1-1.html any和some是等价的,其与all的前面都只能是比较符号,即=, !=, >, <, ...
- 【Python】urlopen小结
0X00 简介 urlopen是urllib的的一个方法,它属于类文件对象,具有文件对象的方法,如read()等,同时也具有自身的一些方法: 1.info() 返回响应包的头信息 2.info() ...
- 从零开始学Linux(11)--more
more命令,是将文件的内容从上到下显示在屏幕上. more会以一页一页的显示方便使用者逐页阅读,而最基本的指令就是按空格键(space)就往下一页显示,按 b 键就会往回(back)一页显示,而且还 ...
- oracle常用DDL语句
1.添加表字段--咨询表添加内容简介字段 ALTER TABLE s_table ADD intro VARCHAR2(1024); COMMENT ON COLUMN s_table.remarks ...
- 如何添加网页QQ在线组件
免费开通QQ推广服务 复制代码到你想要展示的位置 粘贴,完成.
- keepalived+lvs简单实现
一,部署实战环节 01,服务架构图: 服务器镜像为centos6.9 02,服务安装: 10.0.0.10: 下载keeplived官方包--> http://www.keepalived. ...
- C#知识点提要
本篇博文主要对asp.net mvc开发需要撑握的C#语言知识点进行简单回顾,尤其是C# 3.0才有的一些C#语言特性.对于正在学asp.net mvc的童鞋,不防花个几分钟浏览一下.本文要回顾的C# ...
- (转)Cobbler无人值守批量安装Linux系统
本文目录: 1.1 pxe安装系统 1.2 cobbler基本介绍 1.3 安装和配置cobbler 1.3.1 安装cobbler 1.3.2 配置dhcp和tftp 1.4 cobbler从本地光 ...