Chr*_*old 5 c# multithreading asynchronous async-await
我有一个稍微复杂的要求,即并行执行某些任务,并且必须等待其中一些任务完成才能继续.现在,我遇到了意想不到的行为,当我有许多任务时,我想要并行执行,但在ContinueWith处理程序中.我掀起了一个小样本来说明问题:
var task1 = Task.Factory.StartNew(() =>
{
Console.WriteLine("11");
Thread.Sleep(1000);
Console.WriteLine("12");
}).ContinueWith(async t =>
{
Console.WriteLine("13");
var innerTasks = new List<Task>();
for (var i = 0; i < 10; i++)
{
var j = i;
innerTasks.Add(Task.Factory.StartNew(() =>
{
Console.WriteLine("1_" + j + "_1");
Thread.Sleep(500);
Console.WriteLine("1_" + j + "_2");
}));
}
await Task.WhenAll(innerTasks.ToArray());
//Task.WaitAll(innerTasks.ToArray());
Thread.Sleep(1000);
Console.WriteLine("14");
});
var task2 = Task.Factory.StartNew(() =>
{
Console.WriteLine("21");
Thread.Sleep(1000);
Console.WriteLine("22");
}).ContinueWith(t =>
{
Console.WriteLine("23");
Thread.Sleep(1000);
Console.WriteLine("24");
});
Console.WriteLine("1");
await Task.WhenAll(task1, task2);
Console.WriteLine("2");
Run Code Online (Sandbox Code Playgroud)
基本模式是: - 任务1应与任务2并行执行. - 一旦完成第1部分的第一部分,它应该并行执行更多操作.一切都完成后,我想完成.
我期待以下结果:
1 <- Start
11 / 21 <- The initial task start
12 / 22 <- The initial task end
13 / 23 <- The continuation task start
Some combinations of "1_[0..9]_[1..2]" and 24 <- the "inner" tasks of task 1 + the continuation of task 2 end
14 <- The end of the task 1 continuation
2 <- The end
Run Code Online (Sandbox Code Playgroud)
相反,发生的事情是,await Task.WhenAll(innerTasks.ToArray());不会"阻止"继续任务完成.因此,内部任务在外部await Task.WhenAll(task1, task2);完成后执行.结果如下:
1 <- Start
11 / 21 <- The initial task start
12 / 22 <- The initial task end
13 / 23 <- The continuation task start
Some combinations of "1_[0..9]_[1..2]" and 24 <- the "inner" tasks of task 1 + the continuation of task 2 end
2 <- The end
Some more combinations of "1_[0..9]_[1..2]" <- the "inner" tasks of task 1
14 <- The end of the task 1 continuation
Run Code Online (Sandbox Code Playgroud)
相反,如果我使用Task.WaitAll(innerTasks.ToArray()),一切似乎都按预期工作.当然,我不想使用WaitAll,所以我不会阻止任何线程.
我的问题是:
非常感谢任何指针!
您使用了错误的工具。而不是StartNew使用Task.Run. 而不是ContinueWith使用await:
var task1 = Task1();
var task2 = Task2();
Console.WriteLine("1");
await Task.WhenAll(task1, task2);
Console.WriteLine("2");
private async Task Task1()
{
await Task.Run(() =>
{
Console.WriteLine("11");
Thread.Sleep(1000);
Console.WriteLine("12");
});
Console.WriteLine("13");
var innerTasks = new List<Task>();
for (var i = 0; i < 10; i++)
{
innerTasks.Add(Task.Run(() =>
{
Console.WriteLine("1_" + i + "_1");
Thread.Sleep(500);
Console.WriteLine("1_" + i + "_2");
}));
await Task.WhenAll(innerTasks);
}
Thread.Sleep(1000);
Console.WriteLine("14");
}
private async Task Task2()
{
await Task.Run(() =>
{
Console.WriteLine("21");
Thread.Sleep(1000);
Console.WriteLine("22");
});
Console.WriteLine("23");
Thread.Sleep(1000);
Console.WriteLine("24");
}
Run Code Online (Sandbox Code Playgroud)
Task.Run和在这里很优越,因为它们纠正了/await中的许多意外行为。特别是,异步委托和 (for ) 始终使用线程池。StartNewContinueWithTask.Run
我的博客上有更多关于为什么您不应该使用StartNew以及为什么您不应该使用的ContinueWith详细信息。