我有一个使用多线程同时执行30个独立任务的应用程序, 每个任务通过http检索数据,执行计算并将结果返回给ui线程。
我可以使用TPL执行相同的任务吗?
TPL是否创建了30个新线程并将它们分布在所有可用内核上,还是仅将任务分配到可用内核上并且每个内核使用一个线程?
在这种情况下,使用TPL而不是多线程是否会提升性能?
答案 0 :(得分:10)
作为一般规则,没有什么可以阻止TPL使用比核心更多(或更少)的线程。
要使用TPL稍微控制一下情况,我的第一种方法是:确保threadpool max threads setting至少为30,然后将任务与a maximum concurrency level 30并行化。在任务中,你可以在启动CPU绑定计算之前使用信号量来将并发限制为核心数。如果您没有在IIS或SQL服务器下运行,您可以并且可能希望将最小/最大线程池线程数设置为30,以防止线程池启发式过多地播放线程数。 (当然,在您的申请期间,TPL和线程池不会用于其他目的。)
最佳线程数取决于具体情况。 考虑例如您的方案:您的任务在检索数据时不受CPU限制 - 它们是网络绑定的。当您开始执行任务时,最好增加并行性,以便同时执行下载。但是,您的计算可能受CPU限制。在这种情况下,减少线程数以便每个核心只运行一个线程可能会产生更好的性能。
TPL现在基于新的CLR Thread Pool 线程池使用启发式方法来决定线程数 关于新线程池有Channel9 video有一些见解 旧线程池的启发式和有关新线程的一些内容可以be found here (last paragraph "What the Future Holds?")。
在CLR的不同版本中,算法和数字会发生变化 未来也可能是这种情况。
关于并发级别的帖子很多,我遇到的是here。
答案 1 :(得分:9)
我相信TPL通常会为每个核心使用一个线程,除非您明确告诉它使用更多。 可能它将检测何时不够 - 例如在您的情况下,您的任务将花费大部分时间等待数据。
你有什么理由不能使用异步网页抓取吗?我怀疑这里不需要每个任务都有一个线程,甚至不需要每个核心的一个线程。 TPL使异步编程的各个方面更容易,例如continuation。
在效率方面,您的应用程序实际上是CPU绑定的吗?听起来你需要在网络端获得最大的适当并行度 - 这是需要专注的,除非计算真的是重量级。
上面的答案一如既往,但可能会产生误导,因为它在.NET 4.0 CLR中没有一些重要的变化。
正如Andras所说,当前的TPL实现使用了线程池,因此将根据需要使用尽可能多的线程(核心数目现在无关紧要):
任务并行库(TPL)是新类的集合 专门设计,使其更容易和更有效地执行 现代硬件上非常细粒度的并行工作负载。 TPL已经 现在可以单独作为CTP使用,并且包括在内 Visual Studio 2010 CTP,但在这些版本中, 构建在它上面 拥有专用工作计划程序。对于CLR 4.0的Beta 1,默认值 TPL的调度程序将是CLR线程池,它允许TPL样式 工作负载与现有的基于QUWI的代码“玩得很好”,并允许我们 重用线程池中的大部分底层技术 特别是线程注入算法,我们将在其中讨论 未来的职位。
自:
http://blogs.msdn.com/b/ericeil/archive/2009/04/23/clr-4-0-threadpool-improvements-part-1.aspx
答案 2 :(得分:2)
我有一个应用程序,它使用多线程同时执行30个独立任务,每个任务通过http检索数据,执行计算并将结果返回给ui线程。
这是一个IO绑定的并发程序。
我可以使用TPL执行相同的任务吗?
你可以,但TPL是为CPU绑定的并行程序设计的,所以你会滥用它。
TPL是否创建了30个新线程并将它们分布在所有可用内核上,还是仅将任务分配到可用内核上并且每个内核使用一个线程?
都不是。 TPL实质上使用每个核心的无等待工作窃取任务队列来在CPU运行时动态地负载平衡CPU密集型计算。
在这种情况下,使用TPL而不是多线程是否会提升性能?
您将节省30个线程创建以及额外争用您不必要的线程。
解决问题的正确方法是编写一个不阻塞线程的异步程序。这是通过在下载完成后表达计算的剩余部分来完成的,作为在下载完成时使用数据调用的延续。
Microsoft的新F#编程语言包含专门设计的功能,以简化这一过程。例如,您的问题可以通过F#中的5行代码解决:
let fetchCalcAndPost uris calc post =
for uri in uris do
async { use client = new System.Net.WebClient()
let! data = client.AsyncDownloadString uri
do calc data |> post }
|> Async.Start
此解决方案永远不会阻塞任何线程,因此它完全并发。
答案 3 :(得分:0)
你会产生30个线程吗?你是否使用线程池?我相信你的tpl会更加优化。产卵线程是一种相当昂贵的操作。我同意Jon的看法,tpl通常每个核心使用一个线程。我们在这里谈论什么.NET版本b.t.w。