-4

Consider this code on a console application written with vs 2015:

using System; using System.Threading.Tasks; public class Example { public static void Main() { Console.WriteLine("Wait please...."); DateTime time1 = DateTime.Now; Task task1 = MyAsyncFun1(); Task task2 = MyAsyncFun2(); task1.Wait(); task2.Wait(); DateTime time2 = DateTime.Now; Console.WriteLine("time elapsed: " + (time2 - time1).TotalSeconds); Console.ReadLine(); } private static async Task MyAsyncFun1() { await Task.Yield(); System.Threading.Thread.Sleep(2000); } private static async Task MyAsyncFun2() { await Task.Yield(); System.Threading.Thread.Sleep(2000); } } 

There are two methods called asynchronously and all work fine, the 'time elapsed' does not exceeded 2 seconds becouse the execution is parallel.

But when i wrote this code inside an acion method of an ApiController like this:

public class MyController : ApiController { private static async Task MyAsyncFun1() { await Task.Yield(); System.Threading.Thread.Sleep(2000); } private static async Task MyAsyncFun2() { await Task.Yield(); System.Threading.Thread.Sleep(2000); } public async Task<ApiResult> MyAction([FromBody] Mymodel model) { DateTime time1 = DateTime.Now; Task task1 = MyAsyncFun1(); Task task2 = MyAsyncFun2(); task1.Wait(); task2.Wait(); DateTime time2 = DateTime.Now; double d=(time2 - time1).TotalSeconds; return .....; } } 

the execution hang indefinitely on the task1.Wait() statement.

9
  • 7
    I don't see what DI has to do with this, and why would you Wait() when you can await in an async method? Commented Apr 3, 2018 at 11:49
  • 4
    "Don't block on asynchronous code" > never use .Wait() on an async Task method Commented Apr 3, 2018 at 11:50
  • 3
    I see no dependency injection here? Commented Apr 3, 2018 at 11:51
  • 3
    Console applications don't have synchronization contexts. asp.net does ("old" asp.net anyway. I believe they've eliminated it for asp.net core) Commented Apr 3, 2018 at 12:01
  • 3
    @GerriePretorius - he's deadlocking the synchronization context. There's so many examples of this type of problem I don't see any value in constructing yet another answer that points that out. Commented Apr 3, 2018 at 16:17

1 Answer 1

1

Your code is presumably running in ASP.NET (not ASP.NET Core), and has a SynchronizationContext that requires exclusive access, when you block on async code, you risk deadlocking, like you do here.

What is happening here is, chronologically your first awaited incomplete task happens inside MyAsyncFun1, awaiting Task.Yield(), this returns an incomplete task immediately and will later post the continuation (the sleep) back to the current SynchronizationContext.

Later you call .Wait() on task1, which will block until it completes, however it needs the SynchronizationContext to be available, but your waiting blocking thread is using it, so it's a stalemate, deadlock.

You could use .ConfigureAwait(false) on the tasks you are awaiting to ensure they don't require the continuations to be posted back to the current SynchronizationContext, but even better of course is to just await everywhere, and use async top-to-bottom.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.