我在使用 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() 将为传递给它的可枚举集合创建一个新的并行线程。
有什么想法我做错了吗?
它不一定会立即启动每个任务的所有线程。它会检查其工作负载并在处理器的所有核心上进行配置。如果您的任务多于核心,它将停止创建新线程,因为这只会导致大量不必要的上下文切换。但是,如果它认为现有任务/线程被阻止,在这种情况下,它会添加更多线程以便工作可以继续,即启动更多任务,而其他任务被阻止。它不会检测短时间内被阻止的任务。
这可能解释了为什么您没有看到与任务一样多的线程。当任务完成时,系统可以重新使用它所在的线程来放置一个新的、尚未启动的任务。
本博文底部的图表在一定程度上粗略地说明了这一点:http://colinmackay.co.uk/2011/02/08/parallelization-in-net-40-part-1-looping/ http://colinmackay.co.uk/2011/02/08/parallelisation-in-net-40-part-1-looping/。运行最多 4 个任务所需的时间与运行 1 个任务所需的时间大致相同。然后,当添加第 5 个任务时会出现跳转,并且完成所需的时间大致相同,直到第 8 个任务再次跳转时。这是因为我使用的是 4 核系统。
UPDATE
刚刚意识到你的代码永远不会退出任务,因为那里有一个无限循环。我想说任务(离散的工作单元)不是你想要的。除非您专门从任务并行库中获取其他内容,否则在这种情况下,自己使用常规线程可能是更好的解决方案。
对于任务,您几乎无法控制何时创建线程或一次创建多少个线程。 (如果您要从 TPL 获取其他想要保留的内容,您可以编写自己的调度程序来控制这一点)。但是,如果您只是启动一个后台线程,在应用程序的整个生命周期中不断侦听内容,那么我仍然会使用常规线程。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)