要使用多少个线程?

时间:2011-07-07 09:53:07

标签: c# multithreading visual-studio-2010 .net-4.0 threadpool

我知道存在一些现有问题,它们提供了非常好的一般视角。我希望在C#/ VB.Net方面获得一些有关这些观点的实际实现(非哲学)的细节。

我的特殊情况

我有一个WCF服务,除其他外,它接收文件。对于服务的大部分时间而言,这个特定区域实际上只是无所事事 - 当工作确实到来时,它会以极高的数量突然到达。

对于收到的每个文件(最多可以是每秒数千个),服务需要处理文件1-10秒(每个),具体取决于许多其他服务,本地资源和网络IO等待次。

为了帮助使用这些突发工作负载的服务,我实现了一个Queue系统。每秒收到的数千个文件被放置在队列中。控制器根据队列的大小计算要使用的线程数,直到达到“Peak Max Threads”设置,这将阻止它创建其他线程。这些线程放在线程池中,并重用于循环队列。控制器将;每隔一段时间重新计算所需的线程数。如果队列大小减小,则释放相关数量的线程。

古老的问题

我应该达到峰值多少个线程?很明显,每次收到一个文件时添加一个新的线程对于缺少一个更好的词来说是愚蠢的 - 性能最多会恶化。当每个核心的CPU利用率仅为10%时,限制线程,似乎也不是资源的最佳利用。

那么,是否有合适的方法来确定要限制的线程数量?我希望服务可以通过对可用资源进行抽样来确定这一点,但这样做是否会影响性能?我知道常见的答案是监控工作负载,通过反复试验来调整计数,直到找到我喜欢的数字,但由于此服务的性质(长时间闲置,然后是高/突发工作负载),可能需要很长时间是时候得到那种信息了。

如果我们将服务器的图像移动到与第一个更快/更慢/不同的不同主机,那该怎么办?我必须重新重新整理这个过程吗?

理想情况下,我所追求的是协调员智能地增加线程池的大小,直到CPU利用率为x%(80%是合理的?90%?99% ?)。显然,我想这样做而不需要添加超过x%所需的线程,否则所有我最终都会遇到的不仅仅是等待IO资源,而是等待彼此。

提前致谢!


相关问题(如果您需要一些通用的想法):

How many threads to create?

How many threads is too many?

How many threads to create and when?


您的并发症

如果我没有让问题变得更加困难,哪里会很有趣?

目前的情况是,这些服务确实在这些爆发期间达到了100%的cpu。问题是CPU利用率高峰。它从空闲(0-10%)变为100%,然后再次退回。我不确定我能帮到那个 - 理想情况下我不会把它全部带到100%。问题的存在是因为提到的文件实际上是图像,服务过程的一部分是将图像传递给System.Windows.Media黑盒,它为我做了一些复杂的图像处理。 / p>

由于IO等待和其他正在进行的处理,因此峰值之间存在间歇。如果达到100%的峰值无法帮助(我知道如何防止这种情况,或者我应该知道)我应该如何针对CPU利用率图表进行研究?经常坐在100%?弹跳在50-100之间?如果我确实通过抽样来确定哪些效果最好,那么是否可以保证切换虚拟服务器的主机在同一个图表中也能发挥最佳效果?

对于那些愿意回答的人,我不会考虑这种复杂性。随意忽略这一部分。然而,任何答案也解释了这种复杂性,甚至答案只是提供如何处理它的提示,我至少会upvote!

很长一段时间的问题 - 对此感到抱歉 - 感谢您阅读了这么多!!

3 个答案:

答案 0 :(得分:6)

PerformanceCounter允许您查询处理器使用情况。

但是,您是否尝试过框架提供的内容?

        foreach (var file in files)
        {
            var workitem = file;
            Task.Factory.StartNew(() =>
            {
                // do work on workitem
            }, TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness);
        }

您可以在任务中调整任务的并发级别。Factory

默认情况下,.NET 4线程池将调度它在运行它的硬件上最常执行的线程数,但您可以更改其在上一个链接中的工作方式。

可能您需要一个自定义解决方案,但可以使用标准对您进行基准测试。

编辑:(评论说明):

不需要链接,我可能使用了一个发明的术语,因为英语不是我的语言。我的意思是:有一个变量用于存储最后一次检查之前的差异(prevDelta),并将其称为delta。每次“检查”时,将其添加到变量avrageDelta并除以2。你将拥有变量averageDelta,因为你没有任何活动,所以变量很大。然后有另一组delta变量,一个你已经(delta - prevdelta),并将它存储在一个delta变量中,该变量不是所有增量的平均值,而是在很短的时间内的delta的平均值(你必须得出一个准确计算这个时间方差的算法。完成此操作后,您可以比较平均增量和“时间增量”。平均三角洲将大部分低,并且会随着爆发而缓慢上升。在同一时期,时间差异将会非常快。然后你就会遇到爆发停止的情况,平均增量缓慢下降,“时间”变得非常快。

答案 1 :(得分:2)

您可以使用I/O Completion Ports异步获取图像,而不会占用任何线程,直到处理完所有内容为止。

然后,您可以根据客户端PC上的核心数限制您的线程池,确保为其他进程留出核心空间。

答案 2 :(得分:0)

一个动态线程管理器如何监视它们的整体性能并根据这会生成新线程或杀死旧线程?这里的主要问题是如何定义性能测量功能。其余的可以通过周期性调度的作业来完成,该作业根据先前的线程数和在该情况下的性能或类似的事件来增加或减少线程的数量。也许还与资源利用有关(CPU,磁盘,网络......)。

相关问题