await vs Task.Wait - 死锁?

时间:2012-10-30 13:54:08

标签: c# task-parallel-library deadlock async-await

我不太了解Task.Waitawait之间的区别。

我在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时,为什么这不会导致问题?

3 个答案:

答案 0 :(得分:214)

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

Wait将同步阻止,直到任务完成。因此,当前线程被字面上阻止等待任务完成。作为一般规则,您应该一直使用“async”;也就是说,不要阻止async代码。在我的博客上,我会详细介绍how blocking in asynchronous code causes deadlock

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

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

您可能会发现我的async / await intro有帮助。

答案 1 :(得分:0)

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

await 表达式不会阻塞正在执行其的线程。而是,它使编译器将async方法的其余部分注册为等待任务的延续。然后,控制权返回给异步方法的调用方。任务完成后,它将调用其继续,并且异步方法的执行将从中断处继续执行。

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

This article也是不错的读物。

答案 2 :(得分:-1)

其他答案未提供一些重要事实:

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

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

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

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

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

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

“异步等待”会产生许多问题。我们现在不是没有运行时和上下文调试就不会到达await语句。 如果未达到第一次等待,一切都会被阻止。有时甚至可以等待,但一切都被阻止了:

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

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

结论:手动创建任务并对其进行控制要好得多。处理程序对任务给予更多控制。我们可以监视任务并对其进行管理:

https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem

对不起,我的英语。