我正在使用.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个并发运行的任务。每个任务从待处理队列中检索一些元素,执行一些操作,然后尝试为此操作的结果运行嵌套任务。问题是如果元素太多(而(true)模拟这个)并且所有5个任务都在不断运行,则不会启动嵌套任务。只有在while循环的大多数任务完成执行后才能启动。
阻止嵌套任务运行的while语句似乎有问题,但我不知道是什么:)
答案 0 :(得分:3)
Task.Factory.StartNew没有启动任务,它将任务添加到要调度的任务列表中,调度程序根据类似的事情决定何时运行任务;可用核心数(线程池大小),当前CPU负载和现有工作的吞吐量。
您应该在此处阅读有关任务安排的部分:
http://parallelpatterns.codeplex.com/releases/view/48562
PDF格式的第63页。
LongRunning选项通过完全绕过线程池“修复”您的问题。这有一些缺点,它允许您创建比系统真正使用的线程更多的线程,这将通过导致过多的上下文切换来降低性能。
像上面使用线程休眠的代码这样的实验会产生误导,因为它们会“愚弄”调度程序。它看到它增加了更多的工作但CPU负载没有增加。你应该用一个包含数学的紧密循环替换睡眠(例如计算Sqrt()。
为什么不简单地让一个外部循环从队列中读取项目并在Task上执行它们。这样,您的应用程序将充分利用系统的可用并行性而不会使其过载。
以下答案可能值得一看:
答案 1 :(得分:0)
我认为您会发现该库仅根据您可用的核心数大致启动并行任务。即,对于I / O绑定的任务来说,它不是一个很好的选择,在这些任务中你可能真的想要使用比CPU更多的线程。
你并不是说嵌套任务没有启动,是吗?你只是说他们没有在你想要的时候开始,但是稍后再开始。