C# await vs Task.Wait - 死锁?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13140523/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 01:43:52  来源:igfitidea点击:

await vs Task.Wait - Deadlock?

c#task-parallel-librarydeadlockasync-await

提问by ronag

I don't quite understand the difference between Task.Waitand await.

我不太明白之间的差别Task.Waitawait

I have something similar to the following functions in a ASP.NET WebAPI service:

我在 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
    }
}

Where Getwill deadlock.

哪里Get会死机。

What could cause this? Why doesn't this cause a problem when I use a blocking wait rather than await Task.Delay?

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

采纳答案by Stephen Cleary

Waitand await- while similar conceptually - are actually completely different.

Wait并且await——虽然在概念上相似——但实际上完全不同。

Waitwill synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. As a general rule, you should use "asyncall the way down"; that is, don't block on asynccode. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.

Wait将同步阻塞,直到任务完成。所以当前线程实际上被阻塞等待任务完成。一般来说,你应该使用“ asyncall way down”;也就是说,不要阻塞async代码。在我的博客中,我详细介绍了异步代码中的阻塞如何导致死锁

awaitwill asynchronously wait until the task completes. This means the current methodis "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the awaitexpression completes, the remainder of the method is scheduled as a continuation.

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

You also mentioned a "cooperative block", by which I assume you mean a task that you're Waiting on may execute on the waiting thread. There are situations where this can happen, but it's an optimization. There are many situations where it can'thappen, like if the task is for another scheduler, or if it's already started or if it's a non-code task (such as in your code example: Waitcannot execute the Delaytask inline because there's no code for it).

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

You may find my async/ awaitintrohelpful.

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

回答by Ayushmati

Based on what I read from different sources:

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

An awaitexpression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the asyncmethod as a continuation on the awaited task. Control then returns to the caller of the asyncmethod. When the task completes, it invokes its continuation, and execution of the asyncmethod resumes where it left off.

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

To wait for a single taskto complete, you can call its Task.Waitmethod. A call to the Waitmethod blocks the calling thread until the single class instance has completed execution. The parameterless Wait()method is used to wait unconditionally until a task completes. The task simulates work by calling the Thread.Sleepmethod to sleep for two seconds.

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

This articleis also a good read.

这篇文章也很好读。

回答by user1785960

Some important facts were not given in other answers:

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

"async await" is more complex at CIL level and thus costs memory and CPU time.

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

If you must wait until the task end and you do not have nothing more to do you should use Wait() method.

如果您必须等到任务结束并且您无事可做,则应使用 Wait() 方法。

Any task can be canceled if the waiting time is unacceptable.

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

If the task lasts unexpectedly long, you can assume that there has been a deadlock and you need to react and clean up, e.g. by canceling the task.

如果任务持续的时间出乎意料地长,您可以假设出现了死锁,您需要做出反应并进行清理,例如取消任务。

In the case "async await" we do not have a handler for such a task to cancel it or monitoring it.

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

Using Task is more flexible then "async await". Using Wait() method is not obligatory.

使用 Task 比“异步等待”更灵活。使用 Wait() 方法不是必须的。

Any async functionality can by wrapped by async. Any sync functionality can by wrapped by async.

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

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

I do not see why I'm must live with the code duplication fot sync and async method or using hacks.

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