PLINQ:如何在超过 4 个线程上运行 ParallelQuery?
更新 - 更改了问题的标题以反映我真正想要的内容
考虑以下代码:
// this query generates 12 instances of Func<int>, which each when executed
// print something to the console and wait for 1 second.
var actions = Enumerable.Range(0, 12).Select(i => new Func<int>(() =>
{
Console.WriteLine("{0} - waiting 1 sec", i);
Thread.Sleep(1000);
return 1;
}));
// define a parallel query. Note the WithDegreeOfParallelism call here.
var query = from action in actions.AsParallel().WithDegreeOfParallelism(12)
select action();
// execute, measuring total duration
var stopw = Stopwatch.StartNew();
query.ToList();
Console.WriteLine(stopw.Elapsed);
Console.WriteLine(Environment.ProcessorCount); // 3 on my machine
当省略对 WithDegreeOfParallelism
的调用时,这会分 4 个块执行,总共大约需要 4 秒,这是我所期望的,因为我的 CPU 计数是 3。
但是,当使用任何高于 4 的数字调用 WithDegreeOfParallelism
时,我总是得到 3 个块,并且总持续时间不会低于3秒。我希望值 12 的总持续时间为(略多于)1 秒。
我缺少什么?如何强制并行执行 4 个以上的非 CPU 密集型任务,这正是我所追求的?
更新:我当然可以返回手动旋转线程,但我希望新的 PFX 库能让这变得更容易......无论如何,下面的代码给了我大约 1 秒的总执行时间
List<Thread> threads = new List<Thread>();
for (int i = 0; i < 12; i++)
{
int i1 = i;
threads.Add(new Thread(() =>
{
Console.WriteLine(i1);
Thread.Sleep(1000);
}));
}
threads.ForEach(t => t.Start());
threads.ForEach(t => t.Join());
Update - changed the title of the question to reflect what I'm really after
Consider the following piece of code:
// this query generates 12 instances of Func<int>, which each when executed
// print something to the console and wait for 1 second.
var actions = Enumerable.Range(0, 12).Select(i => new Func<int>(() =>
{
Console.WriteLine("{0} - waiting 1 sec", i);
Thread.Sleep(1000);
return 1;
}));
// define a parallel query. Note the WithDegreeOfParallelism call here.
var query = from action in actions.AsParallel().WithDegreeOfParallelism(12)
select action();
// execute, measuring total duration
var stopw = Stopwatch.StartNew();
query.ToList();
Console.WriteLine(stopw.Elapsed);
Console.WriteLine(Environment.ProcessorCount); // 3 on my machine
When omitting the call to WithDegreeOfParallelism
, this executes in 4 chunks, taking about 4 seconds in total, which is what I would expect since my CPU count is 3.
However, when calling WithDegreeOfParallelism
with any number above 4, I always get 3 chunks, and the total duration does not go under 3 seconds. I would expect that a value of 12 would get a total duration of (a little more than) 1 second.
What am I missing? And how can I enforce the parallel execution of more than 4 non-CPU intensive tasks, which is what I'm after?
Update: I could of course go back to manually spinning up threads, but I was hoping that the new PFX library would make this a bit easier... Anyway, the code below gives me about 1 second total execution time
List<Thread> threads = new List<Thread>();
for (int i = 0; i < 12; i++)
{
int i1 = i;
threads.Add(new Thread(() =>
{
Console.WriteLine(i1);
Thread.Sleep(1000);
}));
}
threads.ForEach(t => t.Start());
threads.ForEach(t => t.Join());
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
尝试使用选项
TaskCreationOptions.LongRunning
在并行循环中启动新任务。它们将立即启动,而不是等到线程池上的线程变得可用。Try starting new tasks in your parallel loop with the option
TaskCreationOptions.LongRunning
. They will start right away, instead of waiting until a thread on the threadpool becomes available.正如我所说,WithDegreeOfParallelism 仅设置了一个上限。尝试将任务从 10 增加到 100。最终,您将需要大约 10 秒来完成所有 100 个任务。您的代码适用于具有较小操作的大量任务。
并在任务中添加
Console.WriteLine("{0} 个线程 " ,Process.GetCurrentProcess().Threads.Count);
然后你可以看到创建了多少个线程。(线程计数不是看看 plinq 创建的线程数如何增加)。有很多方法可以使用 PLinq 实现并行性。阅读本文 http://msdn.microsoft.com/en-us/library/ dd997411.aspx。您需要根据相关要求选择最佳方式以获得更好的性能。
As I said WithDegreeOfParallelism is setting only a upper bound.Try increasing your tasks from 10 to 100. You will ended up with around 10 seonds for all 100 of them. Your code is good for larger number of tasks having smaller operations.
and add
Console.WriteLine("{0} threads " ,Process.GetCurrentProcess().Threads.Count);
inside your task then you can see how many threads are created.( Thread count is not the count of plinq created threads. See how it increasing).There are lots of ways to do the parallelism with PLinq . Read this article http://msdn.microsoft.com/en-us/library/dd997411.aspx. You need to choose best way for the relevant requirement to get better performance.
WithDegreeOfParallelism 指示 PLINQ 应创建多少个任务,但不一定要使用多少个线程。
由于任务作为线程池上的工作项执行,因此执行查询的线程数量将受到线程池大小的限制。 ThreadPool 将根据需要添加线程,但这可能需要一段时间 - ThreadPool 可能每秒添加 2 个线程左右。
如果想快速向ThreadPool添加线程,可以使用SetMinThreads方法。如果将此代码放在代码的开头,则测试应在一秒钟左右完成:
您可以决定需要多少个线程,然后使用 SetMinThreads 和 SetMaxThreads 设置 ThreadPool 大小的界限。
WithDegreeOfParallelism dictates how many Tasks should PLINQ create, but not necessarily how many threads will be used.
Since Tasks execute as work items on the ThreadPool, the number of threads executing the query will be limited the size of the ThreadPool. The ThreadPool will add threads as necessary, but it may take a while - ThreadPool may add 2 threads per second or so.
If you want to add threads to the ThreadPool quickly, you can use the SetMinThreads method. If you put this code at the beginning of your code, the test should complete in a second or so:
You can decide how many threads you need, and then use SetMinThreads and SetMaxThreads to set bounds on the ThreadPool size.