Parallel.ForEach不产生所有线程 [英] Parallel.ForEach not spawning all the threads

查看:157
本文介绍了Parallel.ForEach不产生所有线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用Parallel.ForEach时遇到了一些麻烦. 我需要模拟几个硬件组件,它们等待传入的连接并对其进行回复.

I'm having some trouble using Parallel.ForEach. I need to simulate a couple of hardware components, that wait for an incoming connection, and reply to it.

我当前的代码如下:

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();
            }
        }
    });

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

The problem I'm having is: Not every component will get his own thread created. Even if one of the threads exits, they still won't spawn.

我的集合中当前的组件数量为40,产生的线程数为(或至少看起来是)33.

The current amount of components in my collection is 40, the number of threads spawned is (or at least seems to be) 33.

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

I was under the impression that Parallel.Foreach() would create a new, parallel, thread for the enumerable collection passed to it.

有什么想法我在做什么错吗?

Any ideas what I'm doing wrong?

推荐答案

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

It doesn't necessarily start all the threads for each task at once. It looks at its workload and provisions that across all the cores of the processor(s). If you have more tasks than cores it will stop creating new threads as that would just lead to lots of unnecessary context switching. However, if it thinks existing tasks/threads are blocked, in which case it adds more threads so that work can continue, i.e. starting more tasks, while other tasks are blocked. It won't detect blocked tasks for a short period.

这可能可以解释为什么您看不到与任务一样多的线程.任务完成后,系统可以重新使用原来的线程在其上放置一个尚未启动的新任务.

This probably explains why you are not seeing as many threads as tasks. As tasks finish, the system can re-use the thread it was on to put a new, as yet unstarted, task on it.

此博客文章底部的图形在某种程度上大致说明了这一点:

The graph at the bottom of this blog post roughly illustrates this to some extent: http://colinmackay.co.uk/2011/02/08/parallelisation-in-net-40-part-1-looping/. Running up to 4 tasks took about the same length of time as just one. Then there is a jump when the 5th task is added and the time taken to complete was roughly the same up-to the 8th task, when it jumped again. This is because I was on a 4 core system.

更新

仅意识到您的代码将永远不会退出任务,因为其中存在无限循环.我会说任务(是离散的工作单元)不是您想要的.除非您从Task Parallel Library特别获得其他东西,否则在这种情况下,自己使用常规线程可能是更好的解决方案.

Just realised that your code will never exit a task as you have an infinite loop in there. I would say that tasks (which are discrete units of work) are not what you want. Unless there is something else you are specifically getting from the Task Parallel Library then using regular threads yourself may be a better solution in this case.

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

With tasks you have little control over when the threads get created or how many at a time. (You can write your own scheduler to control this if you are getting other things from the TPL you want to preserve). However, if you are simply starting up a background thread that constantly listens for stuff throughout the lifetime of your application then I'd still go with regular threads.

这篇关于Parallel.ForEach不产生所有线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆