问题
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.
My current code is as follows:
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.
The current amount of components in my collection is 40, the number of threads spawned is (or at least seems to be) 33.
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?
回答1:
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.
UPDATE
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.
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.
来源:https://stackoverflow.com/questions/14621976/parallel-foreach-not-spawning-all-the-threads