242

我不太明白 和 之间的Task.Wait区别await

我在 ASP.NET WebAPI 服务中有类似于以下函数的东西:

public class TestController : ApiController
{
    public static async Task<string> Foo()
    {
        await Task.Delay(1).ConfigureAwait(false);
        return "";
    }

    public async static Task<string> Bar()
    {
        return await Foo();
    }

    public async static Task<string> Ros()
    {
        return await Bar();
    }

    // GET api/test
    public IEnumerable<string> Get()
    {
        Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());

        return new string[] { "value1", "value2" }; // This will never execute
    }
}

哪里Get会死机。

什么可能导致这种情况?当我使用阻塞等待而不是 时,为什么这不会导致问题await Task.Delay

4

3 回答 3

335

Waitawait- 虽然在概念上相似 - 实际上是完全不同的。

Wait将同步阻塞,直到任务完成。因此,当前线程实际上被阻塞,等待任务完成。作为一般规则,您应该使用“async一直向下”;也就是说,不要阻塞async代码。在我的博客中,我详细介绍了异步代码中的阻塞如何导致死锁

await将异步等待任务完成。这意味着当前方法“暂停”(其状态被捕获)并且该方法向其调用者返回一个不完整的任务。稍后,当await表达式完成时,该方法的其余部分被安排为延续。

您还提到了一个“合作块”,我假设您的意思是您正在Wait处理的任务可能在等待线程上执行。在某些情况下可能会发生这种情况,但这是一种优化。在许多情况下它不会发生,例如任务是否用于另一个调度程序,或者它已经启动或者它是非代码任务(例如在您的代码示例中:Wait无法Delay内联执行任务,因为没有代码为了它)。

您可能会发现我的async/await介绍很有帮助。

于 2012-10-30T14:19:07.200 回答
16

根据我从不同来源阅读的内容:

await表达式不会阻塞它正在执行的线程。相反,它会导致编译器注册该async方法的其余部分作为等待任务的延续。然后控制权返回给async方法的调用者。当任务完成时,它调用它的继续,并且async方法的执行从它停止的地方继续。

要等待单个task完成,您可以调用其Task.Wait方法。对该Wait方法的调用会阻塞调用线程,直到单个类实例完成执行。无参数Wait()方法用于无条件等待直到任务完成。Thread.Sleep该任务通过调用该方法休眠两秒钟来模拟工作。

这篇文章也很好读。

于 2018-12-06T13:52:53.120 回答
3

其他答案中没有给出一些重要的事实:

“异步等待”在 CIL 级别更复杂,因此会消耗内存和 CPU 时间。

如果等待时间不可接受,任何任务都可以取消。

在“异步等待”的情况下,我们没有处理此类任务的处理程序来取消它或监视它。

使用 Task 比“异步等待”更灵活。

任何同步功能都可以由异步包装。

public async Task<ActionResult> DoAsync(long id) 
{ 
    return await Task.Run(() => { return DoSync(id); } ); 
} 

“异步等待”会产生很多问题。我们现在不是在没有运行时和上下文调试的情况下会到达 await 语句。如果未达到第一个等待,则所有内容都将被阻止。有时甚至等待似乎到达仍然一切都被阻止:

https://github.com/dotnet/runtime/issues/36063

我不明白为什么我必须忍受同步和异步方法或使用黑客的代码重复。

结论:手动创建任务并控制它们要好得多。Task 的处理程序给予更多的控制。我们可以监控任务并管理它们:

https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem

对不起我的英语不好。

于 2020-04-20T13:22:36.353 回答