Coder Perfect

await vs Task.Wait – Deadlock?

Problem

I’m not sure what the difference between Task and Task is. Wait and see what happens.

In an ASP.NET WebAPI service, I have something similar to the following functions:

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 Get will come to a halt.

What could be the reason behind this? When I use a blocking wait instead of await Task.Delay, why does this not cause a problem?

Asked by ronag

Solution #1

Waiting and waiting are theoretically similar, but they are not the same.

Until the task is completed, Wait will synchronously block. As a result, the current thread is stuck waiting for the job to finish. As a general guideline, avoid blocking on async code by using “async all the way down.” On my blog, I explain how deadlock is caused by blocking in asynchronous code.

await will wait asynchronously until the task is finished. This indicates that the current method has been “paused” (its state has been saved) and that the method has returned an incomplete job to its caller. The remainder of the method is scheduled as a continuation after the await expression completes.

You also stated a “cooperative block,” by which I understand you mean that a job you’re Waiting on may run on the waiting thread. This can happen in some circumstances, but it’s an optimization. There are a number of reasons why this won’t work, including if the job is for another scheduler, if it’s already running, or if it’s a non-code task (like in your code example: Wait won’t be able to execute the Delay task inline because it doesn’t have any code).

My async / await introduction could be useful.

Answered by Stephen Cleary

Solution #2

Based on what I’ve learned from various sources:

The thread on which an await expression is running is not blocked. Instead, the rest of the async method is registered as a continuation on the awaited job by the compiler. Control is subsequently passed back to the async method’s caller. When the job is finished, it calls the continuation method, which restarts execution of the async method where it left off.

You can use the Task command to wait for a single task to finish. Method of waiting. The calling thread is blocked until the single class instance has completed execution when the Wait function is called. The parameterless Wait() method is used to wait until a job is completed unconditionally. By invoking the Thread, the job simulates labor. To sleep for two seconds, use this procedure.

This is also a worthwhile read.

Answered by Ayushmati

Solution #3

Other replies omitted some crucial information:

At the CIL level, “async await” is more sophisticated, requiring more memory and CPU time.

If the waiting time is too long, any task can be terminated.

We don’t have a handler for such a job in the case of “async await,” therefore we can’t cancel it or monitor it.

Task provides more flexibility than “async await.”

Async can be used to wrap any sync mechanism.

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

“async await” causes a slew of issues. Without runtime and context debugging, we don’t know if the await statement will be reached. Everything is halted if the first await is not met. Even when await appears to have reached, everything remains blocked:

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

I don’t understand why I have to live with code duplication or hacks for sync and async methods.

Conclusion: It is much better to create tasks manually and control them. Task to Handler gives you more control. Tasks can be monitored and managed in the following ways:

https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem

Please excuse my poor English.

Answered by user1785960

Post is based on https://stackoverflow.com/questions/13140523/await-vs-task-wait-deadlock