0

我在使用 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() 将为传递给它的可枚举集合创建一个新的并行线程。

任何想法我做错了什么?

4

1 回答 1

3

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

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

这篇博文底部的图表在一定程度上大致说明了这一点:http: //colinmackay.co.uk/2011/02/08/parallelisation-in-net-40-part-1-looping/。运行多达 4 个任务所花费的时间与仅运行一个任务所花费的时间大致相同。然后在添加第 5 个任务时发生跳转,完成时间大致相同,直到第 8 个任务再次跳转。这是因为我使用的是 4 核系统。

更新

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

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

于 2013-01-31T09:15:43.963 回答