It seems it is impossible in c# (dotnet core 3.1) to call an asynchronous function from a non-async method without blocking the original thread. Why ?
Code example:
public async Task myMethodAsync() {
await Task.Delay(5000);
}
public void callingMethhod() {
myMethodAsync().Wait(); // all flavours of this expression, like f.ex. .Result seem to be blocking the calling thread
}
What is the technical limitation for being able to release the calling thread until the async method completes, and then continue execution from there? Is it something technically impossible?
Yes, that is expected. That is why the concept of Task etc exist. If it was possible to do what you want: they wouldn't need to - we could just wave a wand and everything would be async. The entire point of awaitable types is that releasing the calling thread while allowing later continuation is hard, and requires coordination and participation from the calling code; and from what ever calls that; etc - all the way up the stack to whatever is running the threads. Your callingMethhod code is synchronous: it has only a few things it can do:
it can run to completion - meaning: it would have to block
it can throw an exception
The impact of this is that async/await is infectious; anything that touches awaitables kinda needs to also be awaitable, which means: you would typically only call myMethodAsync from a callingMethhod that returned a [Value]Task[<T>], and which is presumably async with an await (although those bits aren't strictly necessary in the example shown).
It seems it is impossible in c# (dotnet core 3.1) to call an asynchronous function from a non-async method without blocking the original thread. Why ?
Because that's what synchronous means. Synchronous means it blocks the thread until the method is complete.
What is the technical limitation for being able to release the calling thread until the async method completes, and then continue execution from there? Is it something technically impossible?
If your calling method wants to release its thread, then make it asynchronous. Asynchronous methods are capable of releasing their calling threads. There's nothing impossible here; it's been solved by async and await.
Now, if you're asking "why can't every method implicitly be async", then that is in theory possible, but it causes a couple of major issues. It can never be done in C# for backwards compatibility reasons. The two issues that immediately come to mind are:
Limited interop. It's not possible to use an "everything is async" language to interop with anything that uses old-school threading (Win32 mutexes, et. al.).
Unexpected concurrency. There are a lot of scenarios where developers make an assumption of synchronous code. If every method is potentially asynchronous, then even code as simple as var x = this._list[0]; this._list.RemoveAt(0); is no longer safe.
Related
I've been reading about the new async and await operators in C# and tried to figure out in which circumstances they would possibly be useful to me. I studied several MSDN articles and here's what I read between the lines:
You can use async for Windows Forms and WPF event handlers, so they can perform lengthy tasks without blocking the UI thread while the bulk of the operation is being executed.
async void button1_Click(object sender, EventArgs e)
{
// even though this call takes a while, the UI thread will not block
// while it is executing, therefore allowing further event handlers to
// be invoked.
await SomeLengthyOperationAsync();
}
A method using await must be async, which means that the usage of any async function somewhere in your code ultimately forces all methods in the calling sequence from the UI event handlers up until the lowest-level async method to be async as well.
In other words, if you create a thread with an ordinary good old ThreadStart entry point (or a Console application with good old static int Main(string[] args)), then you cannot use async and await because at one point you would have to use await, and make the method that uses it async, and hence in the calling method you also have to use await and make that one async and so on. But once you reach the thread entry point (or Main()), there's no caller to which an await would yield control to.
So basically you cannot use async and await without having a GUI that uses the standard WinForms and WPF message loop. I guess all that makes indeed sense, since MSDN states that async programming does not mean multithreading, but using the UI thread's spare time instead; when using a console application or a thread with a user defined entry point, multithreading would be necessary to perform asynchronous operations (if not using a compatible message loop).
My question is, are these assumptions accurate?
So basically you cannot use async and await without having a GUI that uses the standard WinForms and WPF message loop.
That's absolutely not the case.
In Windows Forms and WPF, async/await has the handy property of coming back to the UI thread when the asynchronous operation you were awaiting has completed, but that doesn't mean that's the only purpose to it.
If an asynchronous method executes on a thread-pool thread - e.g. in a web service - then the continuation (the rest of the asynchronous method) will simply execute in any thread-pool thread, with the context (security etc) preserved appropriately. This is still really useful for keeping the number of threads down.
For example, suppose you have a high traffic web service which mostly proxies requests to other web services. It spends most of its time waiting for other things, whether that's due to network traffic or genuine time at another service (e.g. a datbase). You shouldn't need lots of threads for that - but with blocking calls, you naturally end up with a thread per request. With async/await, you'd end up with very few threads, because very few requests would actually need any work performed for them at any one point in time, even if there were a lot of requests "in flight".
The trouble is that async/await is most easily demonstrated with UI code, because everyone knows the pain of either using background threads properly or doing too much work in the UI thread. That doesn't mean it's the only place the feature is useful though - far from it.
Various server-side technologies (MVC and WCF for example) already have support for asynchronous methods, and I'd expect others to follow suit.
A method using await must be async, which means that the usage of any async function somewhere in your code ultimately forces all methods in the calling sequence from the UI event handlers up until the lowest-level async method to be async as well.
Not true - methods marked async just mean they can use await, but callers of those methods have no restrictions. If the method returns Task or Task<T> then they can use ContinueWith or anything else you could do with tasks in 4.0
A good non-UI example is MVC4 AsyncController.
Ultimately, async/await is mostly about getting the compiler rewriting so you can write what looks like synchronous code and avoid all the callbacks like you had to do before async/await was added. It also helps with the SynchronizationContext handling, useful for scenarios with thread affinity (UI frameworks, ASP.NET), but even without those, it's still useful. Main can always do DoStuffAsync().Wait(); for instance. :)
My question is, are these assumptions accurate?
No.
You can use async for Windows Forms and WPF event handlers, so they can perform lengthy tasks without blocking the UI thread while the bulk of the operation is being executed.
True. Also true for other UI applications including Silverlight and Windows Store.
And also true for ASP.NET. In this case, it's the HTTP request thread that is not blocked.
A method using await must be async, which means that the usage of any async function somewhere in your code ultimately forces all methods in the calling sequence from the UI event handlers up until the lowest-level async method to be async as well.
This is a best practice ("async all the way down"), but it's not strictly required. You can block on the result of an asynchronous operation; many people choose to do this in Console applications.
an ordinary good old ThreadStart entry point
Well... I do have to take issue with "ordinary good old". As I explain on my blog, Thread is pretty much the worst option you have for doing background operations.
I recommend you review my introduction to async and await, and follow up with the async / await FAQ.
async-await is only wrapper for Task class manipulations, which is part of so named Tasks Parallel Library - TPL(published before async-await auto code generation tech.)
So fact is you may not use any references to UI controls within async - await.
Typically async-await is powerfull tool for any web and server relations, loading resources, sql. It works with smart waiting data with alive UI.
Typically TPL application: from simple big size loop till multi stages parallel calculations in complex calculations based on shared data (ContinueWith and so on)
I recently came across a strange bug in my async code. I was calling a blocking method on a COM control, which appeared to allow my async continuations to run while it was blocking.
Consider example code (illustrative purposes only)
public async void Main()
{
//assume some single threaded dispatcher. eg. WpfDispatcher
Task doAsyncTask = DoAsync();
Console.WriteLine("Start synchronous");
CallSomeCOMControl();
Console.WriteLine("End synchronous");
await doAsyncTask;
}
public async Task DoAsync()
{
Console.WriteLine("Start async");
await Task.Delay(1);
Console.WriteLine("End async");
}
In normal circumstances I would expect the following output:
Start async
Start synchronous
End synchronous
End async
What I was effectively seeing was:
Start async
Start synchronous
End async
End synchronous
Now I do not have the source for the COM control, but I do know that is a very old C++ control that has no notion of async/await. It is however an Active-X control.
I do not know the implementation details of the .Net RCW, but I am assuming that some kind of message pumping must be going on to allow the control to work. I am also assuming that this pumping is allowing my continuations to run.
Are my assumptions correct? And are the any other circumstances that I should be aware of where my supposedly synchronous code could get interrupted?
This is pretty normal, COM will pump when the call crosses an apartment boundary. It has to pump, not doing so is very likely to cause deadlock. It is unclear why that boundary has to be crossed from the snippet, it looks like an STA thread when you talk about WPF. Could be an out-of-process server, could be that you created the object on a worker thread.
It is not fundamentally different from the way the CLR will pump on a WaitOne() or Join() call when you block an STA thread. The re-entrancy headaches that this causes are pretty similar to the kind of misery caused by DoEvents(). Both COM and the CLR pump selectively though, not quite as dangerous. Albeit highly undocumented.
COM apartments greatly simplify threading, taking care of 98% of the usual problems. The last 2% give you a splitting migraine that can be exceedingly hard to solve, re-entrancy is on the top of that list. Only way to address that is to not leave it up to COM to provide the component with a thread-safe home and take care of it yourself. With code like this.
Independently of being awaited or not, the task returned from DoAsync has already started when the method returns.
And you are using a delay of just 1 millisecond.
Have you tried a larger delay?
Why is it possible to do this in C#?
var task = Task.Run (...);
await task;
Isn't Task.Run() supposed to be used for CPU-bound code? Does it make sense to call awaitfor this?
I.e., after calling Task.Run I understand that the task is running in another thread of the thread pool. What's the purpose of calling await? Wouldn't make more sense just to call task.Wait()?
One last question, my first impression was that await is intended to be used exclusively with async methods. Is it common to use it for task returned by Task.Run()?
EDIT. It also makes me wonder, why do we have Task.Wait () and not a Task.Await(). I mean, why a method is used for Wait() and a keyworkd for await. Wouldn't be more consistent to use a method in both cases?
There would be no point at all in using Wait. There's no point in starting up a new thread to do work if you're just going to have another thread sitting there doing nothing waiting on it. The only sensible option of those two is to await it. Awaiting a task is entirely sensible, as it's allowing the original thread to continue execution.
It's sensible to await any type of Task (in the right context), regardless of where it comes from. There's nothing special about async methods being awaited. In fact in every single asynchronous program there needs to be asynchronous methods that aren't using the async keyword; if every await is awaiting an async method then you'll never have anywhere to start.
There are several good answers here, but from a more philosophical standpoint...
If you have lots of CPU-bound work to do, the best solution is usually the Task Parallel Library, i.e., Parallel or Parallel LINQ.
If you have I/O-bound work to do, the best solution is usually async and await code that is built around naturally-asynchronous implementations (e.g., Task.Factory.FromAsync).
Task.Run is a way to execute a single piece of CPU-bound code and treat it as asynchronous from the point of view of the calling thread. I.e., if you want to do CPU-bound work but not have it interfere with the UI.
The construct await Task.Run is a way to bridge the two worlds: have the UI thread queue up CPU-bound work and treat it asynchronously. This is IMO the best way to bridge asynchronous and parallel code as well, e.g., await Task.Run(() => Parallel.ForEach(...)).
why a method is used for Wait() and a keyword for await.
One reason that await is a keyword is because they wanted to enable pattern matching. Tasks are not the only "awaitables" out there. WinRT has its own notion of "asynchronous operations" which are awaitable, Rx observable sequences are awaitable, Task.Yield returns a non-Task awaitable, and this enables you to create your own awaitables if necessary (e.g., if you want to avoid Task allocations in high-performance socket applications).
Yes, it's common and recommended. await allows to wait for a task (or any awaitable) asynchronously. It's true that it's mostly used for naturally asynchronous operations (e.g. I/O), but it's also used for offloading work to be done on a different thread using Task.Run and waiting asynchronously for it to complete.
Using Wait not only blocks the calling thread and so defeats the purpose of using Task.Run in the first place, it could also potentially lead to deadlocks in a GUI environment with a single threaded synchronization context.
One last question, my first impression was that await is intended to be used exclusively with async methods
Whether a method is actually marked with the async modifier is an implementation detail and most "root" task returning methods in .Net aren't actually async ones (Task.Delay is a good example for that).
Wouldn't make more sense just to call task.Wait()?
No, if you call Wait you're involving two threads there, one of the worker threads from the ThreadPool is working for you (given the task is CPU bound), and also your calling thread will be blocked.
Why would you block the calling thread? The result will be too bad if the calling thread is a UI thread! Also if you call Task.Run immediately followed by Task.Wait you're making it worse, too. It is no better than calling the delegate synchronously. There is no point whatsoever in calling Wait immediately after starting a Task.
You should almost never use Wait, always prefer await and release the calling thread.
It is very common and useful for cases like (greatly simplified; production code would need exception handling, for instance):
async void OnButtonClicked()
{
//... Get information from UI controls ...
var results = await Task.Run(CpuBoundWorkThatShouldntBlockUI);
//... Update UI based on results from work run in the background ...
}
Regarding the comment of your later edit, 'await' is not a method call. It is a keyword (only allowed in a method that has been marked 'async', for clarity) that the compiler uses to decide how to implement the method. Under the hood, this involves rewriting the method procedure as a state machine that can be paused every time you use the 'await' keyword, then resumed when whatever is it awaiting calls back to indicate that it is done. This is a simplified description (exception propagation and other details complicate things), but the key point is that 'await' does a lot more than just calling a method on a Task.
In previous C# versions, the closest construct to this 'async/await' magic was the use of 'yield return' to implement IEnumerable<T>. For both enumerations and async methods, you want a way to pause and resume a method. The async/await keywords (and associated compiler support) start with this basic idea of a resumable method, then add in some powerful features like automatic propagation of exceptions, dispatching callbacks via a synchronization context (mostly useful to keep code on the UI thread) and automatic implementation of all the glue code to set up the continuation callback logic.
I have a library that exposes synchronous and asynchronous versions of a method, but under the hood, they both have to call an async method. I can't control that async method (it uses async/await and does not use ConfigureAwait(false)), nor can I replace it.
The code executes in the context of an ASP .NET request, so to avoid deadlocks, here's what I've done:
var capturedContext = SynchronizationContext.Current;
try
{
// Wipe the sync context, so that the bad library code won't find it
// That way, we avoid the deadlock
SynchronizationContext.SetSynchronizationContext(null);
// Call the async method and wait for the result
var task = MyMethodAsync();
task.Wait();
// Return the result
return task.Result;
}
finally
{
// Restore the sync context
SynchronizationContext.SetSynchronizationContext(capturedContext);
}
Does this produce the same effect as if MyMethodAsync had used ConfigureAwait(false) on all of its await's? Are there some other problems with this approach that I'm overlooking?
(MyMethodAsync is completely unaware that it's being run in an ASP .NET context, it doesn't do any calls to HttpContext.Current or anything like that. It just does some async SQL calls, and the writer didn't put ConfigureAwait(false) on any of them)
I have a library that exposes synchronous and asynchronous versions of a method, but under the hood, they both have to call an async method.
The library is wrong to expose a synchronous version. Just pretend the synchronous API doesn't exist.
so to avoid deadlocks
There shouldn't be any problems with deadlocks if you call an asynchronous method that uses async/await. If it doesn't use ConfigureAwait(false), then it's not as efficient as it could be, that's all. Deadlocks due to ConfigureAwait(false) only apply when you're trying to do sync-over-async (i.e., if you're calling the synchronous APIs from that library).
So, the easiest and simplest solution is to just ignore the synchronous APIs, which are incorrectly designed anyway:
return await MyMethodAsync();
Provided you wrap this technique in a suitably named static function, I think your suggest is significantly better than Task.Run, even if still the lesser of two evils.
Task.Run has a number of issues:
It is not clear why you are using it, you want to start a new task on a web server? This will be deleted by new developers fast if there are no comments. And then boom, difficult to diagnose production issues (deadlocks).
It starts on a new thread pool thread when it doesn't need to until it reaches its first await completed continuation.
It makes you block synchronously for the entire Task returning function, when from your description of the problem, the blocking is actually just part of the overall task. What is being encouraged here is longer blocking over async code, this is certainly not what you want.
If you use it multiple levels, you are multiplying the problem (with SetSynchronizationContext there's no harm in doing it more than once).
If it turns out that there was no blocking / deadlock where you thought there was, or it had been fixed, Task.Run now is introducing blocking over async, whereas SetSynchronizationContext will not cost you anything, in addition to the optimizations it makes by not resuming on the context constantly.
I also understand there is hesitance to make any recommendation given blocking on async code should be avoided at all costs, however you have made it clear you are aware of this and this is to fix a known case of this outside of your immediate control. I think the dogmatic attitude towards this topic is damaging to the .NET ecosystem.
Setting the SynchronizationContext to null seems hacky for me. Instead you can really delegate the work to threadpool. Use Task.Run..
var result = Task.Run(() => MyMethodAsync()).Result;
or
var result = Task.Run(async () => await MyMethodAsync()).Result;
This avoids the deadlock and eliminates the hacky code as well.
I've been reading about the new async and await operators in C# and tried to figure out in which circumstances they would possibly be useful to me. I studied several MSDN articles and here's what I read between the lines:
You can use async for Windows Forms and WPF event handlers, so they can perform lengthy tasks without blocking the UI thread while the bulk of the operation is being executed.
async void button1_Click(object sender, EventArgs e)
{
// even though this call takes a while, the UI thread will not block
// while it is executing, therefore allowing further event handlers to
// be invoked.
await SomeLengthyOperationAsync();
}
A method using await must be async, which means that the usage of any async function somewhere in your code ultimately forces all methods in the calling sequence from the UI event handlers up until the lowest-level async method to be async as well.
In other words, if you create a thread with an ordinary good old ThreadStart entry point (or a Console application with good old static int Main(string[] args)), then you cannot use async and await because at one point you would have to use await, and make the method that uses it async, and hence in the calling method you also have to use await and make that one async and so on. But once you reach the thread entry point (or Main()), there's no caller to which an await would yield control to.
So basically you cannot use async and await without having a GUI that uses the standard WinForms and WPF message loop. I guess all that makes indeed sense, since MSDN states that async programming does not mean multithreading, but using the UI thread's spare time instead; when using a console application or a thread with a user defined entry point, multithreading would be necessary to perform asynchronous operations (if not using a compatible message loop).
My question is, are these assumptions accurate?
So basically you cannot use async and await without having a GUI that uses the standard WinForms and WPF message loop.
That's absolutely not the case.
In Windows Forms and WPF, async/await has the handy property of coming back to the UI thread when the asynchronous operation you were awaiting has completed, but that doesn't mean that's the only purpose to it.
If an asynchronous method executes on a thread-pool thread - e.g. in a web service - then the continuation (the rest of the asynchronous method) will simply execute in any thread-pool thread, with the context (security etc) preserved appropriately. This is still really useful for keeping the number of threads down.
For example, suppose you have a high traffic web service which mostly proxies requests to other web services. It spends most of its time waiting for other things, whether that's due to network traffic or genuine time at another service (e.g. a datbase). You shouldn't need lots of threads for that - but with blocking calls, you naturally end up with a thread per request. With async/await, you'd end up with very few threads, because very few requests would actually need any work performed for them at any one point in time, even if there were a lot of requests "in flight".
The trouble is that async/await is most easily demonstrated with UI code, because everyone knows the pain of either using background threads properly or doing too much work in the UI thread. That doesn't mean it's the only place the feature is useful though - far from it.
Various server-side technologies (MVC and WCF for example) already have support for asynchronous methods, and I'd expect others to follow suit.
A method using await must be async, which means that the usage of any async function somewhere in your code ultimately forces all methods in the calling sequence from the UI event handlers up until the lowest-level async method to be async as well.
Not true - methods marked async just mean they can use await, but callers of those methods have no restrictions. If the method returns Task or Task<T> then they can use ContinueWith or anything else you could do with tasks in 4.0
A good non-UI example is MVC4 AsyncController.
Ultimately, async/await is mostly about getting the compiler rewriting so you can write what looks like synchronous code and avoid all the callbacks like you had to do before async/await was added. It also helps with the SynchronizationContext handling, useful for scenarios with thread affinity (UI frameworks, ASP.NET), but even without those, it's still useful. Main can always do DoStuffAsync().Wait(); for instance. :)
My question is, are these assumptions accurate?
No.
You can use async for Windows Forms and WPF event handlers, so they can perform lengthy tasks without blocking the UI thread while the bulk of the operation is being executed.
True. Also true for other UI applications including Silverlight and Windows Store.
And also true for ASP.NET. In this case, it's the HTTP request thread that is not blocked.
A method using await must be async, which means that the usage of any async function somewhere in your code ultimately forces all methods in the calling sequence from the UI event handlers up until the lowest-level async method to be async as well.
This is a best practice ("async all the way down"), but it's not strictly required. You can block on the result of an asynchronous operation; many people choose to do this in Console applications.
an ordinary good old ThreadStart entry point
Well... I do have to take issue with "ordinary good old". As I explain on my blog, Thread is pretty much the worst option you have for doing background operations.
I recommend you review my introduction to async and await, and follow up with the async / await FAQ.
async-await is only wrapper for Task class manipulations, which is part of so named Tasks Parallel Library - TPL(published before async-await auto code generation tech.)
So fact is you may not use any references to UI controls within async - await.
Typically async-await is powerfull tool for any web and server relations, loading resources, sql. It works with smart waiting data with alive UI.
Typically TPL application: from simple big size loop till multi stages parallel calculations in complex calculations based on shared data (ContinueWith and so on)