在调用.WaitAll()C#后,向列表<Task>添加匿名任务不会执行它

Der*_*tic 3 .net c# asynchronous task

我通过以下方式将任务添加到任务列表中

taskList.Add(new Task(async () =>
    {
        // work here
        await MethodInsideThatNeedsAwaiting(); // if that has anything to do with it
        // more work 
    }));
Run Code Online (Sandbox Code Playgroud)

Task.WaitAll(tasklist);之后的电话会被"卡住".该程序继续运行,但是从该列表中的任何任务都没有听到任何声音,也没有触及任何断点,就像它在某个地方卡在自己的内部异步循环中一样.

我将这个任务添加到列表错误的方式是什么?这是什么问题?

我也尝试了:
我也尝试了以下内容,如果由于某种原因async关键字是问题,但它仍然不起作用:

taskList.Add(new Task(() =>
    {
        // work here
        MethodInsideThatNeedsAwaiting().Wait();
        // more work 
    }));
Run Code Online (Sandbox Code Playgroud)

然而,这可以按预期工作

private async Task GetStuff()
{
    // same work here
    await MethodInsideThatNeedsAwaiting();
    // more work
}
Run Code Online (Sandbox Code Playgroud)

然后使用taskList.Add(GetStuff());Calling 添加它就Task.WaitAll(tasklist);没有问题.

Eri*_*ert 11

你在这里做的一切都是错的.在编写更多异步代码之前,停止正在进行的操作并了解其工作原理.你正在为从未完成的任务做好准备,因为他们从未开始,而且因为他们在等待自己而从未完成的任务.异步工作流程有点棘手.

首先:你几乎不想使用new Task.它只是意味着"创造一个代表这项工作的任务".它并不意味着执行该工作. new Task制作待办事项列表; 它没有做清单上的东西!

其次,你几乎不想使用Task.Run.这意味着创建一个代表工作的任务,并从池中分配一个工作人员来运行它.除非您正在进行的工作是同步的并且受CPU限制,否则您不希望分配工作程序,而您的工作不是.

第三,你几乎从不想在任何已经成为任务的事情上使用它们.你手头有一个异步lambda.它在调用时返回一个任务,因此如果您想要一个正在运行的工作流的任务,请调用lambda!

第四,你几乎从不想WaitAll. 通过将异步工作流程转换回同步工作流程,这破坏了异步的整个过程.

第五,Wait出于同样的原因,你几乎从不想要任务.但它变得更糟!这是我希望你做的待办事项清单:首先,将面包放入烤面包机并开始烘烤.第二,同步等待三明治完成; 在此步骤完成之前不要继续.第三,吃三明治.第四,当烤面包机爆炸时,从烤面包机中取出烤面包,并在烤面包上放一些火腿做三明治. 如果您尝试执行此工作流程,您将永远等待.当您将同步等待插入到它们中时,异步工作流会发生死锁,因为您经常处于等待您将来要做的工作的情况.

(关于最后一点:如果您处于这种情况,正确的解决方案是不要改变工作流程的第二步"雇用一名工人完成我的三明治,并同步等待该工人完成".你.经常看到这种奇怪的,浪费的修复不正确的工作流程. 当您删除同步等待并await在工作流无法继续直到任务完成的点处插入异步等待()时,您会发现您的工作流程可以完成所有工作线程.)

你正在做的每件事都是完成异步编程的错误方法,如果你继续这样做就不会成功.

好的,既然你知道怎么不这样做,你怎么做的?

  • 如果您有返回任务的方法或lambda,请调用它来获取任务.
  • 如果您需要等待该任务完成,然后工作流才能继续,则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
}
Run Code Online (Sandbox Code Playgroud)

如果您有多个任务并且想要等待所有任务,但他们不必等待彼此怎么办?

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
}
Run Code Online (Sandbox Code Playgroud)

如果您有不明数量的此类任务怎么办?

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
}
Run Code Online (Sandbox Code Playgroud)