我应该使用ThreadPools或任务并行库进行IO绑定操作

在我的一个项目中,这是一个聚合器,我从网上parsing源,播客等等。

如果我使用顺序方法,考虑到大量资源,处理所有资源需要相当长的时间(由于networking问题和类似的东西);

foreach(feed in feeds) { read_from_web(feed) parse(feed) } 

所以我想要实现并发性,并不能决定是否应该基本上使用ThreadPools来处理工作线程或只是依靠TPL来进行sorting。

ThreadPools肯定会用工作线程来处理我的工作,我会得到我所期望的(在多核CPU环境下,其他核心也将被使用)。

并发

但是我仍然想考虑TPL,因为它是推荐方法,但我有点担心。 首先我知道TPL使用ThreadPools,但增加了额外的决策层。 我主要关心的是单核环境存在的情况。 如果我没有错,TPL从一开始就有一个数字的工作线程开始,等于可用CPU内核的数量。 我害怕TPL在序列方法上产生类似的结果,这是我的IO界限的情况。

所以对于IO绑定的操作(在我的情况下,从网上读取资源),是最好使用ThreadPools和控制的东西,或者更好的只是依靠TPL? TPL也可以用于IO界限的情况吗?

更新 :我主要关心的是 – 在单核CPU环境下,TPL只是performance得像顺序方法,还是会提供并发性? 我已经阅读了与Microsoft .NET并行编程,所以这本书,但无法find一个确切的答案。

注意:这是我以前的问题的重新措辞[ 是否可以一起使用线程并发和并行? ]这是错误的措词。

所以我决定为此编写testing,并在实际数据中看到它。

testing图例

  • Itr:迭代
  • Seq:顺序方法。
  • PrlEx:并行扩展 – Parallel.ForEach
  • TPL:任务并行库
  • TPool:ThreadPool

检测结果

单核CPU [Win7-32​​] – 在VMWare下运行 –

 Test Environment: 1 physical cpus, 1 cores, 1 logical cpus. Will be parsing a total of 10 feeds. ________________________________________________________________________________ Itr. Seq. PrlEx TPL TPool ________________________________________________________________________________ #1 10.82s 04.05s 02.69s 02.60s #2 07.48s 03.18s 03.17s 02.91s #3 07.66s 03.21s 01.90s 01.68s #4 07.43s 01.65s 01.70s 01.76s #5 07.81s 02.20s 01.75s 01.71s #6 07.67s 03.25s 01.97s 01.63s #7 08.14s 01.77s 01.72s 02.66s #8 08.04s 03.01s 02.03s 01.75s #9 08.80s 01.71s 01.67s 01.75s #10 10.19s 02.23s 01.62s 01.74s ________________________________________________________________________________ Avg. 08.40s 02.63s 02.02s 02.02s ________________________________________________________________________________ 

单核CPU [WinXP] – 在VMWare下运行 –

 Test Environment: 1 physical cpus, NotSupported cores, NotSupported logical cpus. Will be parsing a total of 10 feeds. ________________________________________________________________________________ Itr. Seq. PrlEx TPL TPool ________________________________________________________________________________ #1 10.79s 04.05s 02.75s 02.13s #2 07.53s 02.84s 02.08s 02.07s #3 07.79s 03.74s 02.04s 02.07s #4 08.28s 02.88s 02.73s 03.43s #5 07.55s 02.59s 03.99s 03.19s #6 07.50s 02.90s 02.83s 02.29s #7 07.80s 04.32s 02.78s 02.67s #8 07.65s 03.10s 02.07s 02.53s #9 10.70s 02.61s 02.04s 02.10s #10 08.98s 02.88s 02.09s 02.16s ________________________________________________________________________________ Avg. 08.46s 03.19s 02.54s 02.46s ________________________________________________________________________________ 

双核CPU [Win7-64]

 Test Environment: 1 physical cpus, 2 cores, 2 logical cpus. Will be parsing a total of 10 feeds. ________________________________________________________________________________ Itr. Seq. PrlEx TPL TPool ________________________________________________________________________________ #1 07.09s 02.28s 02.64s 01.79s #2 06.04s 02.53s 01.96s 01.94s #3 05.84s 02.18s 02.08s 02.34s #4 06.00s 01.43s 01.69s 01.43s #5 05.74s 01.61s 01.36s 01.49s #6 05.92s 01.59s 01.73s 01.50s #7 06.09s 01.44s 02.14s 02.37s #8 06.37s 01.34s 01.46s 01.36s #9 06.57s 01.30s 01.58s 01.67s #10 06.06s 01.95s 02.88s 01.62s ________________________________________________________________________________ Avg. 06.17s 01.76s 01.95s 01.75s ________________________________________________________________________________ 

四核CPU [Win7-64] – 支持HyprerThreading –

 Test Environment: 1 physical cpus, 4 cores, 8 logical cpus. Will be parsing a total of 10 feeds. ________________________________________________________________________________ Itr. Seq. PrlEx TPL TPool ________________________________________________________________________________ #1 10.56s 02.03s 01.71s 01.69s #2 07.42s 01.63s 01.71s 01.69s #3 11.66s 01.69s 01.73s 01.61s #4 07.52s 01.77s 01.63s 01.65s #5 07.69s 02.32s 01.67s 01.62s #6 07.31s 01.64s 01.53s 02.17s #7 07.44s 02.56s 02.35s 02.31s #8 08.36s 01.93s 01.73s 01.66s #9 07.92s 02.15s 01.72s 01.65s #10 07.60s 02.14s 01.68s 01.68s ________________________________________________________________________________ Avg. 08.35s 01.99s 01.75s 01.77s ________________________________________________________________________________ 

概要

  • 无论您是在单核环境还是多核环境下运行,并行扩展,TPL和ThreadPool都具有相同的性能,并提供近似的结果
  • TPL仍然具有简单的exception处理,取消支持和轻松返回任务结果的优势 。 尽pipe并行扩展也是另一个可行的select。

自行运行testing

你可以在这里下载源代码并运行你自己的。 如果您可以发布结果,我也会添加它们。

更新:修复了源代码链接。

如果您想为IO界限的任务最大化吞吐量,那么您绝对必须将传统的asynchronous处理模型(APM)API与基于TPL的工作结合起来。 当asynchronousIOcallback挂起时,APM API是解除阻塞CPU线程的唯一方法。 TPL提供TaskFactory::FromAsync帮助器方法来帮助组合APM和TPL代码。

查看MSDN上名为TPL和Traditional .NET Asynchronous Programming的.NET SDK的这一部分,了解如何结合这两种编程模型实现asynchronous涅</s>的更多信息。

你是对的,当你创build自己的线程池时,TPL会删除你拥有的一些控制权。 但是,如果你不想深入挖掘,这只是正确的。 TPL允许您创build长期运行的任务,这些任务不属于TPL线程池,可以很好地满足您的需求。 已发表的这本书是一本免费阅读的使用Microsoft .NET并行编程的书籍,将使您更深入地了解TPL是如何使用的。 您始终可以selectPara​​lle.For,Tasks 显式参数分配多less个线程。 除此之外,如果您想完全控制,您可以用您自己的replaceTPL调度程序。

您可以将您自己的任务计划程序分配给TPL任务。 但是, 窃取一个的默认工作是非常聪明的。

我害怕TPL在序列方法上产生类似的结果,这是我的IO界限的情况。

我想会的。 什么是瓶颈? 是parsing还是下载? 从网上下载multithreading对你来说无能为力。

我会使用任务并行库进行裁剪,为下载的图像应用蒙版或效果,从播客中剪切一些样本等。它更具可扩展性。

但这不会是数量级的加速。 花你的资源来实现一些function,testing。

PS。 “哇我的function在0.7秒而不是0.9”;)

如果你把你的调用并行化,那么即使只有一个核心,我认为它会改善你的应用程序。 看看这个代码:

 var client = new HttpClient(); var urls = new[]{"a", "url", "to", "find"}; // due to the EAP pattern, this will run in parallel. var tasks = urls.Select(c=> client.GetAsync(c)); var result = Tasks.WhenAll(task).ContinueWith(a=> AnalyzeThisWords(a.Result)); result.Wait(); // don't know if this is needed or it's correct to call wait 

在这种情况下,multithreading和asynchronous之间的区别在于callback/完成是如何完成的。

使用EAP时,任务的数量与线程数量无关。

由于您依赖于GetAsync任务,http客户端使用networkingstream(socket,tcp客户端或其他)并在BeginRead / EndRead完成时发出信号来引发事件。 所以,这个时候不涉及线程。

完成调用后,可能会创build一个新的线程,但是取决于TaskScheduler(用于调用GetAsync / ContinueWith调用)创build一个新的线程,使用现有的线程或内联任务以使用调用线程。

如果AnalyzeThisWords阻塞了太多时间,那么随着ContinueWith上的“callback”由线程池工作者完成,您就开始遇到瓶颈。