我通过以下方式将任务添加到任务列表中
taskList.Add(new Task(async () =>
{
// work here
await MethodInsideThatNeedsAwaiting(); // if that has anything to do with it
// more work
}));
此后调用Task.WaitAll(tasklist);
会“卡住”。该程序继续运行,但是该列表中的任何任务都不再有任何消息,也没有遇到任何断点,就好像它陷入了自己的内部异步循环中一样。
将任务添加到列表的方式是否错误?这是什么问题?
我也尝试过:
我也尝试了以下方法,如果由于某种原因async
关键字是问题所在,但它仍然 无效 :
taskList.Add(new Task(() =>
{
// work here
MethodInsideThatNeedsAwaiting().Wait();
// more work
}));
但是 可以按预期
private async Task GetStuff()
{
// same work here
await MethodInsideThatNeedsAwaiting();
// more work
}
然后将其添加到taskList.Add(GetStuff());
中,调用Task.WaitAll(tasklist);
对此没有任何问题。
答案 0 :(得分:11)
您在这里所做的一切都是错误的。 在编写更多异步代码之前,请停止正在做的事情,并了解其工作原理。您正在为无法完成的任务(因为它们从未开始执行)以及无法完成的任务(正在等待它们)进行设置对自己。异步工作流有些棘手。
首先,您几乎永远不想使用new Task
。它只是意味着“做一个代表这项工作的任务”。 这并不意味着要执行该工作。 new Task
列出待办事项;它没有做清单上的东西!
第二,您几乎永远不想使用Task.Run
。这意味着要做一个代表工作的任务,并从池中分配一个工人来运行它。。除非您正在执行的工作是同步和 CPU绑定,而您没有工作,否则您就不想分配工作线程。
第三,您几乎永远都不想在已经已完成任务的某项上使用。您手中有一个异步lambda。 调用时它返回一个任务,因此,如果您想要一个正在运行的工作流的任务,请调用lambda!
第四,您几乎永远不想WaitAll
。 通过将异步工作流变回同步工作流来破坏整个异步点。
第五,出于相同的原因,您几乎永远不想在任务上调用Wait
。但情况变得更糟!这是我希望您执行的任务清单:首先,将面包放入烤面包机中,然后开始烘烤。其次,同步等待三明治完成;在完成此步骤之前,请勿继续前进。第三,吃三明治。第四,当烤面包机弹出时,将烤面包机从烤面包机中取出,并在烤面包机上放一些火腿做一个三明治。 如果您尝试执行此工作流程,将永远等待。异步工作流死锁,当您在其中插入同步等待时,因为您经常处于等待自己将来要做的工作的情况中。 >
(除了最后一点:如果您处在这种情况下,正确的解决方案是 NOT 将工作流程的第二步更改为“雇用工人同步完成我的三明治”等待该工作人员完成。”您经常会看到这种奇怪的,浪费的解决方法,用于错误的工作流程。当您删除同步等待并在工作流程无法继续的地方插入异步等待(await
)时直到完成一项任务,然后您就会发现您的工作流可以全部由一个线程完成。)
您所做的每一件事绝对都是错误的异步编程方式,如果您继续这样做下去就不会成功。
好的,现在您知道了如何不做,如何做?
await
完成该任务。WhenAll
以取回代表完成所有任务的新任务这些任务。然后,您必须await
那个任务。一些正确的工作流程:
这是最简单的一个:
private async Task GetStuffAsync()
{
// same work here
await MethodInsideThatNeedsAwaitingAsync();
// more work
}
private async Task DoItAsync()
{
// do work
await GetStuffAsync();
// do more work
}
如果您有多个任务并且想要等待所有任务,但又不必彼此等待怎么办?
private async Task DoItAsync()
{
// do work
Task t1 = GetStuffAsync();
// do work
Task t2 = GetOtherStuffAsync();
// do more work
// We cannot continue until both are done
await t1;
await t2;
// do even more work
}
如果您有 个这样的任务,该怎么办?
private async Task DoItAsync()
{
// do work
var tasks = new List<Task>();
while (whatever)
tasks.Add(GetStuffAsync());
// do work
// we cannot continue until all tasks are done
await Task.WhenAll(tasks);
// do more work
}