任务并行库。嵌套任务不启动
我正在使用 .NET 新的 TPL 库,并面临一些我无法解释的奇怪行为。由于某种原因,在我的情况下,嵌套任务没有启动。我已将解决方案简化为以下内容:
bool flag = false;
for (int i = 0; i < 5; i++)
{
Task.Factory.StartNew(() =>
{
while (true) // a lot of newcoming tasks
{
Thread.Sleep(200); //do some work
Task.Factory.StartNew(() =>
{
flag = true;
});
}
});
}
Thread.Sleep(2000);
Assert.IsTrue(flag);
我有 5 个同时运行的任务。每个任务从挂起队列中检索一些元素,执行一些操作,然后尝试运行嵌套任务以获得该操作的结果。问题是,如果元素太多(while(true) 模拟了这一点)并且所有 5 个任务都在不断运行,则嵌套任务不会启动。只有在大多数带有 while 循环的任务完成执行后才能启动。
while 语句似乎有问题,会阻止嵌套任务运行,但我不知道是什么:)
I'm working with .NET new TPL library and faced with some strange behavior for me I cannot explain. For some reason nested task is not started in my case. I've simplified the solution I have to the following:
bool flag = false;
for (int i = 0; i < 5; i++)
{
Task.Factory.StartNew(() =>
{
while (true) // a lot of newcoming tasks
{
Thread.Sleep(200); //do some work
Task.Factory.StartNew(() =>
{
flag = true;
});
}
});
}
Thread.Sleep(2000);
Assert.IsTrue(flag);
I have 5 Tasks that running concurrently. Each tasks retrieve some elements from pending queue, performs some operation and then try to run nested task for the results of this operation. The problem is that if there are too many elements (while(true) simulates this) and all 5 tasks are constantly running nested tasks are not started. The can only be started after most of tasks with while loop finish their execution.
It seems something wrong with while statements that blocks nested tasks to run, but I don't know what :)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Task.Factory.StartNew 不会启动任务,它将任务添加到要计划的任务列表中,并且调度程序可以根据以下内容决定何时运行任务:可用核心数量(线程池大小)、当前 CPU 负载和现有工作的吞吐量。
您应该在此处阅读有关任务调度的部分:
http://parallelpatterns.codeplex.com/releases/ view/48562
PDF 第 63 页起。
LongRunning 选项通过完全绕过线程池来“修复”您的问题。这有一些缺点,因为它允许您创建比系统实际使用的线程更多的线程,这会导致过多的上下文切换,从而降低性能。
像上面使用线程睡眠的代码这样的实验具有误导性,因为它们“欺骗”了调度程序。它发现它增加了更多工作,但 CPU 负载并未增加。63 您应该用包含数学的紧密循环替换睡眠(例如计算 Sqrt())。
为什么不简单地使用一个读取项目的外部循环从队列中执行它们并在任务上执行它们,这样您的应用程序将充分利用系统的可用并行性,而不会使其过载,
以下答案可能值得一看:
并行任务库 WaitAny 设计
Task.Factory.StartNew doesn't start a task, it adds the task to the list of tasks to be scheduled and the scheduler gets to decide when to run the task based on things like; number of available cores (size of thread pool), current CPU load and the throughput of existing work.
You should read the section about task scheduling here:
http://parallelpatterns.codeplex.com/releases/view/48562
Page 63 of the PDF onwards.
The LongRunning option "fixes" your problem by bypassing the thread pool entirely. This has some disadvantages in that it will allow you to create more threads than your system should really be using, this will degrade the performance by causing excessive context switching.
Experiments like the code you have above using thread sleep are misleading because they "fool" the scheduler. It sees that it added more work and yet the CPU load hasn't increased.63 You should replace the sleep with a tight loop which contains math (like calculating Sqrt() for example.
Why not simply have a single outer loop which reads items from a queue and executes them on Task. That way your application will make the most use of available parallelism of the system without overloading it.
The following answer might be worth a look:
Parallel Task Library WaitAny Design
我想您会发现该库仅大致根据可用核心的数量启动并行任务。也就是说,对于 I/O 绑定的任务来说,这不是一个好的选择,在这些任务中,您可能实际上想要使用比 CPU 多得多的线程。
您并不是真的说嵌套任务不会启动,是吗?你只是说他们没有在你希望的时候开始,而是稍后开始。
I think you'll find that the library only starts parallel tasks roughly based on the number of cores you have available. i.e. it's not a good choice for tasks which are I/O bound where you might actually want to use significantly more threads than you have CPUs.
You're not really saying that the nested tasks don't start, are you? You're just saying that they don't get started at the point you'd like them to, but start later.