背景:
我有一个控制台应用程序,它创建 Tasks
来处理来自数据库的数据(我们称它们为 Level1 任务)。每个任务再次创建自己的任务以处理分配给它的数据的每个部分(Level2 任务)。
每个 Level2 任务都有一个与之关联的延续任务,代码用于在继续之前对延续任务执行 WaitAll
。
我在 .NET 4.0
(没有 async
/await
)
问题:
但这会产生一个问题 - 结果表明,如果这样做,则在安排所有可用的 Level1 任务之前,没有任何 Level2 任务会启动。这在任何方面都不是最优的。
问题:
这似乎可以通过更改代码以等待原始 Level2 任务及其后续任务来解决。但是,我不完全确定为什么会这样。
你有什么想法吗?
我唯一能想到的是 - 由于延续任务尚未开始,因此等待它完成是没有意义的。但即使是这样,我也希望至少有一些 Level2 任务已经开始。他们从未这样做过。
示例:
我创建了一个示例控制台应用程序来演示该行为:
按原样运行它,您会看到它首先安排所有任务,然后您才开始获取从 Level2 任务中写入的实际行。
但是注释掉标记的代码块并取消注释替换,一切都按预期工作。
你能告诉我为什么吗?
public class Program
{
static void Main(string[] args)
{
for (var i = 0; i < 100; i++)
{
Task.Factory.StartNew(() => SomeMethod());
//Thread.Sleep(1000);
}
Console.ReadLine();
}
private static void SomeMethod()
{
var numbers = new List<int>();
for (var i = 0; i < 10; i++)
{
numbers.Add(i);
}
var tasks = new List<Task>();
foreach (var number in numbers)
{
Console.WriteLine("Before start task");
var numberSafe = number;
/* Code to be replaced START */
var nextTask = Task.Factory.StartNew(() =>
{
Console.WriteLine("Got number: {0}", numberSafe);
})
.ContinueWith(task =>
{
Console.WriteLine("Continuation {0}", task.Id);
});
tasks.Add(nextTask);
/* Code to be replaced END */
/* Replacement START */
//var originalTask = Task.Factory.StartNew(() =>
//{
// Console.WriteLine("Got number: {0}", numberSafe);
//});
//var contTask = originalTask
// .ContinueWith(task =>
// {
// Console.WriteLine("Continuation {0}", task.Id);
// });
//tasks.Add(originalTask);
//tasks.Add(contTask);
/* Replacement END */
}
Task.WaitAll(tasks.ToArray());
}
}
最佳答案
我认为您看到了 Task Inlining
行为。引自 MSDN :
In some cases, when a Task is waited on, it may be executed synchronously on the Thread that is performing the wait operation. This enhances performance, as it prevents the need for an additional Thread by utilizing the existing Thread which would have blocked, otherwise. To prevent errors due to re-entrancy, task inlining only occurs when the wait target is found in the relevant Thread's local queue.
您不需要 100 个任务来查看此内容。我已将您的程序修改为具有 4 个 1 级任务(我有四核 CPU)。每个 1 级任务只会创建一个 2 级任务。
static void Main(string[] args)
{
for (var i = 0; i < 4; i++)
{
int j = i;
Task.Factory.StartNew(() => SomeMethod(j)); // j as level number
}
}
在您的原始程序中,nextTask
是延续任务 - 所以我只是简化了方法。
private static void SomeMethod(int num)
{
var numbers = new List<int>();
// create only one level 2 task for representation purpose
for (var i = 0; i < 1; i++)
{
numbers.Add(i);
}
var tasks = new List<Task>();
foreach (var number in numbers)
{
Console.WriteLine("Before start task: {0} - thread {1}", num,
Thread.CurrentThread.ManagedThreadId);
var numberSafe = number;
var originalTask = Task.Factory.StartNew(() =>
{
Console.WriteLine("Got number: {0} - thread {1}", num,
Thread.CurrentThread.ManagedThreadId);
});
var contTask = originalTask
.ContinueWith(task =>
{
Console.WriteLine("Continuation {0} - thread {1}", num,
Thread.CurrentThread.ManagedThreadId);
});
tasks.Add(originalTask); // comment and un-comment this line to see change in behavior
tasks.Add(contTask); // same as adding nextTask in your original prog.
}
Task.WaitAll(tasks.ToArray());
}
这是示例输出 - 关于注释 tasks.Add(originalTask);
- 这是你的第一个 block 。
Before start task: 0 - thread 4
Before start task: 2 - thread 3
Before start task: 3 - thread 6
Before start task: 1 - thread 5
Got number: 0 - thread 7
Continuation 0 - thread 7
Got number: 1 - thread 7
Continuation 1 - thread 7
Got number: 3 - thread 7
Continuation 3 - thread 7
Got number: 2 - thread 4
Continuation 2 - thread 4
还有一些示例输出 - 关于保持 tasks.Add(originalTask);
这是你的第二个 block
Before start task: 0 - thread 4
Before start task: 1 - thread 6
Before start task: 2 - thread 5
Got number: 0 - thread 4
Before start task: 3 - thread 3
Got number: 3 - thread 3
Got number: 1 - thread 6
Got number: 2 - thread 5
Continuation 0 - thread 7
Continuation 1 - thread 7
Continuation 3 - thread 7
Continuation 2 - thread 4
正如您在第二种情况下看到的那样,当您在启动它的同一线程上等待 originalTask
时,任务内联
将使它在同一线程上运行 - 这是为什么您之前看到 Got Number..
消息。
关于c# - 继续任务上的 Task.WaitAll() 只会延迟原始任务的执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22024879/