2013-02-22 09:52:29 8 Comments
I came across some best practices for asynchronous programming using c#'s async
/await
keywords (I'm new to c# 5.0).
One of the advices given was the following:
Stability: Know your synchronization contexts
... Some synchronization contexts are non-reentrant and single-threaded. This means only one unit of work can be executed in the context at a given time. An example of this is the Windows UI thread or the ASP.NET request context. In these single-threaded synchronization contexts, it’s easy to deadlock yourself. If you spawn off a task from a single-threaded context, then wait for that task in the context, your waiting code may be blocking the background task.
public ActionResult ActionAsync()
{
// DEADLOCK: this blocks on the async task
var data = GetDataAsync().Result;
return View(data);
}
private async Task<string> GetDataAsync()
{
// a very simple async method
var result = await MyWebService.GetDataAsync();
return result.ToString();
}
If I try to dissect it myself, the main thread spawns to a new one in MyWebService.GetDataAsync();
, but since the main thread awaits there, it waits on the result in GetDataAsync().Result
. Meanwhile, say the data is ready. Why doesn't the main thread continue it's continuation logic and returns a string result from GetDataAsync()
?
Can someone please explain me why there is a deadlock in the above example? I'm completely clueless about what the problem is ...
Related Questions
Sponsored Content
17 Answered Questions
[SOLVED] Using async/await with a forEach loop
- 2016-06-01 18:55:58
- saadq
- 380885 View
- 884 Score
- 17 Answer
- Tags: javascript node.js promise async-await ecmascript-2017
11 Answered Questions
[SOLVED] How to safely call an async method in C# without await
- 2013-03-20 11:59:06
- George Powell
- 162222 View
- 288 Score
- 11 Answer
- Tags: c# exception async-await task task-parallel-library
1 Answered Questions
[SOLVED] Why does this async/await code NOT cause a deadlock?
- 2017-06-14 11:54:25
- Yeldar Kurmangaliyev
- 561 View
- 4 Score
- 1 Answer
- Tags: c# asynchronous async-await task-parallel-library
8 Answered Questions
[SOLVED] Why can't I use the 'await' operator within the body of a lock statement?
- 2011-09-30 15:23:00
- Kevin
- 88825 View
- 319 Score
- 8 Answer
- Tags: c# .net async-await
21 Answered Questions
[SOLVED] How and when to use ‘async’ and ‘await’
- 2013-01-22 09:29:58
- Dan Dinu
- 784975 View
- 992 Score
- 21 Answer
- Tags: c# .net asynchronous async-await
24 Answered Questions
[SOLVED] How would I run an async Task<T> method synchronously?
- 2011-02-23 18:18:27
- Rachel
- 364378 View
- 608 Score
- 24 Answer
- Tags: c# asynchronous c#-5.0 async-await
6 Answered Questions
[SOLVED] HttpClient.GetAsync(...) never returns when using await/async
- 2012-04-27 01:28:07
- Benjamin Fox
- 170180 View
- 298 Score
- 6 Answer
- Tags: c# .net asynchronous async-await dotnet-httpclient
5 Answered Questions
[SOLVED] Using async/await for multiple tasks
- 2012-09-09 08:40:04
- Ben Foster
- 227042 View
- 382 Score
- 5 Answer
- Tags: c# .net task-parallel-library async-await c#-5.0
2 Answered Questions
[SOLVED] Async-Await no deadlock where a deadlock is expected
- 2015-12-26 10:39:12
- Anirudh
- 435 View
- 3 Score
- 2 Answer
- Tags: c# asynchronous async-await deadlock synchronizationcontext
1 Answered Questions
[SOLVED] cannot replicate deadlock on async await
- 2015-08-20 16:03:12
- Sean
- 116 View
- 5 Score
- 1 Answer
- Tags: c# .net async-await task-parallel-library deadlock
5 comments
@cuongle 2013-02-22 10:37:37
Take a look at this example, Stephen has a clear answer for you:
Another link you should read: Await, and UI, and deadlocks! Oh my!
@Herre Kuijpers 2018-06-29 09:12:48
I was just fiddling with this issue again in an ASP.NET MVC project. When you want to call
async
methods from aPartialView
, you're not allowed to make thePartialView
async
. You'll get an exception if you do.You can use the following simple workaround in the scenario where you want to call an
async
method from a sync method:SynchronizationContext
SynchronizationContext
Example:
@Orace 2018-09-26 09:58:07
A work around I came to is to use a
Join
extension method on the task before asking for the result.The code look's like this:
Where the join method is:
I'm not enough into the domain to see the drawbacks of this solution (if any)
@Phillip Ngan 2017-05-11 10:01:23
GetDataAsync().Result;
will run when the task returned byGetDataAsync()
completes, in the meantime it blocks the UI threadreturn result.ToString()
) is queued to the UI thread for executionGetDataAsync()
will complete when its queued continuation is runDeadlock!
The deadlock can be broken by provided alternatives to avoid Fact 1 or Fact 2.
var data = await GetDataAsync()
, which allows the UI thread to keep runningvar data = Task.Run(GetDataAsync).Result
, which will post the continuation to the sync context of a threadpool thread. This allows the task returned byGetDataAsync()
to complete.This is explained really well in an article by Stephen Toub, about half way down where he uses the example of
DelayAsync()
.@marvelTracker 2016-04-19 22:51:35
Another main point is that you should not block on Tasks, and use async all the way down to prevent deadlocks. Then it will be all asynchronous not synchronous blocking.
@Dexter 2017-02-06 15:35:31
What if I want the main (UI) thread to be blocked until the task finishes? Or in a Console app for example? Let's say I want to use HttpClient, which only supports async... How do I use it synchronously without the risk of deadlock? This must be possible. If WebClient can be used that way (because of having sync methods) and works perfectly, then why couldn't it be done with HttpClient too?
@Jeroen 2017-12-22 19:58:45
See answer from Philip Ngan above (i know this was posted after this comment): Queue the continuation of the await to a different thread that is not blocked, e.g. use var data = Task.Run(GetDataAsync).Result
@ToolmakerSteve 2018-06-27 19:41:16
@Dexter - re "What if I want the main (UI) thread to be blocked until the task finishes?" - do you truly want the UI thread blocked, meaning user can't do anything, can't even cancel - or is it that you don't want to continue the method you are in? "await" or "Task.ContinueWith" handle the latter case.
@Dexter 2018-11-28 00:07:00
@ToolmakerSteve of course I don't want to continue the method. But I simply cannot use await because I cannot use async all the way either - HttpClient is invoked in main, which of course cannot be async. And then I mentioned doing all this in a Console app - in this case I want exactly the former - I don't want my app to even be multi-threaded. Block everything.