Parallel.ForEach不会产生所有线程

时间:2013-01-31 09:07:22

标签: .net multithreading parallel.foreach

我在使用Parallel.ForEach时遇到了一些麻烦。 我需要模拟一些等待传入连接的硬件组件,然后回复它。

我目前的代码如下:

Task.Factory.StartNew(() => components, (component) =>
    {
        var listener = new TcpListener(component.Ip, component.Port);
        while(true)
        {
            using(var socket = listener.AcceptSocket())
            {
                 //Read out socket and send a reply
                 socket.Close();
            }
        }
    });

我遇到的问题是:并非每个组件都会创建自己的线程。 即使其中一个线程退出,它们仍然不会产生。

我的集合中当前的组件数量是40,产生的线程数是(或者至少似乎是)33。

我的印象是Parallel.Foreach()会为传递给它的可枚举集合创建一个新的并行线程。

任何想法我做错了什么?

1 个答案:

答案 0 :(得分:3)

它不一定一次启动每个任务的所有线程。它着眼于处理器所有核心的工作负载和规定。如果你有比核心更多的任务,它将停止创建新线程,因为这只会导致大量不必要的上下文切换。但是,如果它认为现有任务/线程被阻止,则在这种情况下它会添加更多线程,以便可以继续工作,即启动更多任务,同时阻止其他任务。它不会在短时间内检测到被阻止的任务。

这可能解释了为什么你没有看到与任务一样多的线程。当任务完成后,系统可以重新使用它所使用的线程,在其上放置一个新的,尚未启动的任务。

此博客文章底部的图表大致说明了这一点:http://colinmackay.co.uk/2011/02/08/parallelisation-in-net-40-part-1-looping/。运行最多4个任务所花费的时间与仅一个任务相同。然后在添加第5个任务时跳转,并且完成所需的时间与第8个任务大致相同,当它再次跳跃时。这是因为我使用的是4核心系统。

<强>更新

刚才意识到你的代码永远不会退出任务,因为你在那里有一个无限循环。我会说任务(这是离散的工作单元)不是你想要的。除非您从Task Parallel Library中获得其他内容,否则在这种情况下使用常规线程可能是更好的解决方案。

使用任务,您几乎无法控制创建线程的时间或一次控制多少线程。 (如果要从要保留的TPL中获取其他内容,您可以编写自己的调度程序来控制它。但是,如果您只是在应用程序的整个生命周期中启动一个不断监听内容的后台线程,那么我仍然会使用常规线程。

相关问题