I have a strange behaviour concerning wrapping asynchronous methods in C#.
It is difficult to cut out the portion of my code that has this strange behaviour, so instead I made a test project to investigate the behaviour, and this is what I have found out.
I have a test class which has an async method that is simply a wrapper of another async method: (In my original code it is a wrapper class which contains 2 objects, which it has wrapper methods for)
public class Test
{
public async Task Delay()
{
await Task.Delay(1000);
}
}
In my test program I am running the following code from an async event handler: (In my case the Loaded event, since I am using a WPF Window)
var test = new Test();
await Task.Delay(1000);
await test.Delay();
Task.Delay(1000).Wait();
test.Delay().Wait();
All is well until the last line, which never returns.
Then I tried changing the test class to the following and the last line works:
public class Test
{
public Task Delay()
{
return Task.Delay(1000);
}
}
My question is why the first scenario does not work?
I describe this deadlock scenario in detail on my blog and in an MSDN article.
By default, when you await a task, it will capture the current "context" (SynchronizationContext.Current unless it is null, in which case it captures TaskScheduler.Current). When the async method resumes, it resumes in that context.
In your case, the UI context is captured, and your async method is attempting to resume on the UI thread after the delay completes. However, it cannot resume execution because the UI thread is blocked waiting for the task to complete.
The best solution is to use async "all the way"; in other words, don't block on async code.
By default the await keyword is built to try to keep as much of the original code as possible running on the original thread (or, at least, in the same "context" as the code that runs before the await, e.g. if you were running in the thread pool previously, any thread pool thread will do).
What's happening is that all of your original code, when it can run, wants to run on the UI thread.
But you're blocking the UI thread in that Wait so it's never available to run the remainder of the code inside your async method and so complete the outer Task. I.e. there's just this little bit of code left to run in your method, after the Task.Delay task has completed:
public class Test
{
public async Task Delay()
{
await Task.Delay(1000);
//<-- This "Code" needs to run before my Task is completed
}
}
You can use ConfigureAwait(continueOnCapturedContext) to request that this not happen:
continueOnCapturedContext
true to attempt to marshal the continuation back to the original context captured; otherwise, false.
See also this old blog post by Eric Lippert, from when async was new:
The “async” modifier on the method does not mean “this method is automatically scheduled to run on a worker thread asynchronously”. It means the opposite of that; it means “this method contains control flow that involves awaiting asynchronous operations and will therefore be rewritten by the compiler into continuation passing style to ensure that the asynchronous operations can resume this method at the right spot.” The whole point of async methods it that you stay on the current thread as much as possible.
Related
I was reading this article and found this example:
public static class DeadlockDemo
{
private static async Task DelayAsync()
{
await Task.Delay(1000);
}
// This method causes a deadlock when called in a GUI or ASP.NET context.
public static void Test()
{
// Start the delay.
var delayTask = DelayAsync();
// Wait for the delay to complete.
delayTask.Wait();
}
}
The root cause of this deadlock is due to the way await handles contexts. By default, when an incomplete Task is awaited, the current “context” is captured and used to resume the method when the Task completes. This “context” is the current SynchronizationContext unless it’s null, in which case it’s the current TaskScheduler. GUI and ASP.NET applications have a SynchronizationContext that permits only one chunk of code to run at a time. When the await completes, it attempts to execute the remainder of the async method within the captured context. But that context already has a thread in it, which is (synchronously) waiting for the async method to complete. They’re each waiting for the other, causing a deadlock.
I understand that if there was code after await Task.Delay(1000);, it would be part of the continuation, and that continuation would be running in the same context as Test(), and that's how the deadlock would happen.
However, there is no continuation, so how does the deadlock actually happen?
Or, is there an empty continuation that is created? What would be the point in that?
This is the part that is confusing me:
When the await completes, it attempts to execute the remainder of the
async method within the captured context.
What is the "remainder of the async method"?
If we're an async Task or async Task<T> method, then there's always work to do after the await - we need to ensure that any exception produced by the awaited task is properly propagated to our own Task, or that we pass the appropriate normal return value through.
If we're any kind of async method using structures such as using which insert compiler-generated code at the end of an otherwise appearing empty epilogue to our method, then we'll be inserting code at the end of the method, even if it doesn't appear in the source.
If we're any normal async method that liberally uses awaits then we'll already have a state machine built and running to execute our method and there's no point in optimizing the "no code after the last await" possibility.
In the narrow case that we're an async void1 method that contains a single await at the end, then other than some minutiae about where an unhandled exception from a task might be reported, we already had the opportunity to avoid excess code generation by not making the method async at all and just ignoring the awaitable.
So there's no reason to try to optimize this situation.
1We're already in a state of sin at that point anyway.
I've been trying to understand async/await and Task in C# but have been failing spectacularly despite watching youtube videos, reading documentation and following a pluralsight course.
I was hoping someone might be able to help answer these slightly abstract questions to help my brain out.
1.Why do they say that async/await enables an 'asynchonrous' method when the async keyword on it's own does nothing and the await keyword adds a suspension point? Isn't adding a suspension point forcing the method to act synchronously, i.e. finish the task marked by the await before moving on.
2.Apparently you are not supposed to use async void except for event handlers, so how do you call an async method normally? It seems that in order to call an async method by using the await keyword, the method/class that is calling it itself needs to be marked as async. All the examples I've seen have 'initiated' an async void method with an event handler. How would you 'escape' this wrapping of async/await to run the method?
3.
public async Task SaveScreenshot(string filename, IWebDriver driver)
{
var screenshot = driver.TakeScreenshot();
await Task.Run(() =>
{
Thread.Sleep(2000);
screenshot.SaveAsFile(filename, ScreenshotImageFormat.Bmp);
Console.WriteLine("Screenshot saved");
});
Console.WriteLine("End of method");
}
Relating back to 1. this looks like a synchronous method. Execution pauses when it gets to Task.Run, therefore Console.WriteLine("End of method"); will not be executed until the task is finished. Maybe the whole method itself will be executed asynchronously at the point it is triggered in the code? But relating back to 2, you need to call this with an await otherwise you get the message 'Because this call is not awaited..' therefore adding an await will cause that execution point to be synchronous and so on and so.
Any help understanding this would be much appreciated.
Isn't adding a suspension point forcing the method to act synchronously, i.e. finish the task marked by the await before moving on.
No, the word you're thinking of is "sequential", not "synchronous". await results in asynchronous sequential code. "Sequential" meaning "one at a time"; "synchronous" meaning "blocking until completed".
how do you call an async method normally?
Using await.
How would you 'escape' this wrapping of async/await to run the method?
Ideally, you don't. You go async all the way. Modern frameworks (including ASP.NET MVC, Azure Functions / WebJobs, NUnit / xUnit / MSTest, etc) all allow you to have entry points that return Task. Less-modern frameworks (including WinForms, WPF, Xamarin Forms, ASP.NET WebForms, etc) all allow async void entry points.
So, ideally you do not call asynchronous code from synchronous code. This makes sense if you think about what asynchronous code is: the entire point of it is to not block the calling thread, so if you block the calling thread on asynchronous code, then you lose all the benefits of asynchronous code in the first place.
That said, there are rare situations where you do need to treat the code synchronously. E.g., if you are in the middle of a transition to async, or if you are constrained by a library/framework that is forcing your code to be synchronous and won't work with async void. In that case, you can employ one of the hacks in my article on brownfield async.
Your understanding is pretty good :). The main point you seem to be missing is that "asynchronous" methods in .NET mean methods that can stop execution without blocking the calling thread.
As you pointed out in (1), the async keyword basically enables the use of await and requires the return type to be void or Task/Task<T>. await just instructs the current method to suspend execution until the task is complete.
What you are missing here is that it suspends just the current method. It does not block the thread the method was executing on. This is important in cases like the UI thread of a WPF application. Suspend method execution and everything keeps running, block the thread and the application stops responding.
You usually want your async calls to go all the way to the top (like an event handler), this allows the most flexibility and prevents deadlock situations. However; you can wait for a Task returning method to complete with Wait:
someAsyncMethod.Wait()
Or get the return value:
var result = someAsyncMethod.Result;
Note that both of these are synchronous and block the calling thread. Doing this can cause deadlock if the async task is waiting for some other work on the calling thread to complete.
The above should answer your question in (3); the method itself appears to execute synchronously (this is the magic of await/async) but the task doesn't block the calling thread.
It is asynchronous because you don't have to wait the method to return. In your code, you may call the async method and save the task in a variable. Continue doing something else. Later, when the method result is needed, you await the response (task).
// Synchronous method.
static void Main(string[] args)
{
// Call async methods, but don't await them until needed.
Task<string> task1 = DoAsync();
Task<string> task2 = DoAsync();
Task<string> task3 = DoAsync();
// Do other stuff.
// Now, it is time to await the async methods to finish.
Task.WaitAll(task1, task2, task3);
// Do something with the results.
Console.WriteLine(task1.Result);
Console.ReadKey();
}
private static async Task<string> DoAsync()
{
Console.WriteLine("Started");
await Task.Delay(3000);
Console.WriteLine("Finished");
return "Success";
}
// Output:
// Started
// Started
// Started
// Finished
// Finished
// Finished
// Success
In this code:
public async Task v_task()
{
await Task.Run(() => Console.WriteLine("Hello!"));
}
public async void v1()
{
await v_task();
// some other actions...
}
public void ButtonClick()
{
v1();
Console.WriteLine("Hi!");
}
Which methods above are actually executed in parallel in the async/await generated lower thread pool if ButtonClick is called?
I mean, what should be my concerns about race conditions working with async/await? All async methods are mandatory executed in the same caller's thread? Should I use mutex on possible shared state? If yes, how could I detect what are the shared state objects?
Which methods above are actually executed in parallel in the async/await generated lower thread pool if ButtonClick is called?
Only the Console.WriteLine within the Task.Run.
I mean, what should be my concerns about race conditions working with async/await?
I suggest you start by reading my async intro, which explains how await actually works.
In summary, async methods are usually written in a serially asynchronous fashion. Take this code for example:
CodeBeforeAwait();
await SomeOtherMethodAsync();
CodeAfterAwait();
You can always say that CodeBeforeAwait will execute to completion first, then SomeOtherMethodAsync will be called. Then our method will (asynchronously) wait for SomeOtherMethodAsync to complete, and only after that will CodeAfterAwait be called.
So it's serially asynchronous. It executes in a serial fashion, just like you'd expect it to, but also with an asynchronous point in that flow (the await).
Now, you can't say that CodeBeforeAwait and CodeAfterAwait will execute within the same thread, at least not without more context. await by default will resume in the current SynchronizationContext (or the current TaskScheduler if there is no SyncCtx). So, if the sample method above was executed in the UI thread, then you would know that CodeBeforeAwait and CodeAfterAwait will both execute on the UI thread. However, if it was executed without a context (i.e., from a background thread or Console main thread), then CodeAfterAwait may run on a different thread.
Note that even if parts of a method run on a different thread, the runtime takes care of putting any barriers in place before continuing the method, so there's no need to barrier around variable access.
Also note that your original example uses Task.Run, which explicitly places work on the thread pool. That's quite different than async/await, and you will definitely have to treat that as multithreaded.
Should I use mutex on possible shared state?
Yes. For example, if your code uses Task.Run, then you'll need to treat that as a separate thread. (Note that with await, it's a lot easier to not share state at all with other threads - if you can keep your background tasks pure, they're much easier to work with).
If yes, how could I detect what are the shared state objects?
Same answer as with any other kind of multi-threaded code: code inspection.
If you call an async function, your thread will perform this function until it reaches an await.
If you weren't using async-await, the thread would yield processing until the awaited code was finished and continue with the statement after the await.
But as you are using async-await, you told the compiler that whenever the thread has to wait for something, you have some other things it can do instead of waiting, The thread will do those other things until you say: now await until your original thing is finished.
Because of the call to an async function we are certain that somewhere inside there should be an await. Note that if you call an async function that doesn't await you get a compiler warning that the function will run synchronously.
Example:
private async void OnButton1_clickec(object sender, ...)
{
string dataToSave = ...;
var saveTask = this.MyOpenFile.SaveAsync(dataToSave);
// the thread will go into the SaveAsync function and will
// do all things until it sees an await.
// because of the async SaveAsync we know there is somewhere an await
// As you didn't say await this.MyOpenfile.SaveAsync
// the thread will not wait but continue with the following
// statements:
DoSomethingElse()
await saveTask;
// here we see the await. The thread was doing something else,
// finished it, and now we say: await. That means it waits until its
// internal await is finished and continues with the statements after
// this internal await.
Note that even if the await somewhere inside SaveAsync was finished, the thread will not perform the next statement until you await SaveTask. This has the effect that DoSomethingElse will not be interrupted if the await inside the SaveAsync was finished.
Therefore normally it's not useful to create an async function that does not return either a Task or a Task < TResult >
The only exception to this is an event handler. The GUI doesn't have to wait until your event handler is finished.
I don't quite understand the difference between Task.Wait and await.
I have something similar to the following functions in a ASP.NET WebAPI service:
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 deadlock.
What could cause this? Why doesn't this cause a problem when I use a blocking wait rather than await Task.Delay?
Wait and await - while similar conceptually - are actually completely different.
Wait will 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 "async all the way down"; that is, don't block on async code. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.
await will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await expression completes, the remainder of the method is scheduled as a continuation.
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't happen, 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: Wait cannot execute the Delay task inline because there's no code for it).
You may find my async / await intro helpful.
Based on what I read from different sources:
An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
To wait for a single task to complete, you can call its Task.Wait method. A call to the Wait method 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.Sleep method to sleep for two seconds.
This article is also a good read.
Some important facts were not given in other answers:
async/await is more complex at CIL level and thus costs memory and CPU time.
Any task can be canceled if the waiting time is unacceptable.
In the case of async/await we do not have a handler for such a task to cancel it or monitoring it.
Using Task is more flexible than async/await.
Any sync functionality can by wrapped by async.
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
async/await generate many problems. We do not know if await statement will be reached without runtime and context debugging. If first await is not reached, everything is blocked. Sometimes even when await seems to be reached, still everything is blocked:
https://github.com/dotnet/runtime/issues/36063
I do not see why I must live with the code duplication for sync and async method or using hacks.
Conclusion: Creating Tasks manually and controlling them is much better. Handler to Task gives more control. We can monitor Tasks and manage them:
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
Sorry for my english.
Is there a C# equivalent of F#'s StartImmediate which can be executed on a Task? I have a situation where I need to await a function sometimes, but other times I just want the method to call back to the UI thread without using await.
I want to avoid async void if possible.
Example:
public async void DoSomething()
{
//before runs on UI thread
await OtherThing();
//after runs on UI thread
}
public async Task DoSomethingElse()
{
//before runs on UI thread
await OtherThing();
//I want this to run on the UI thread
}
public void CallDoSomething()
{
DoSomething(); //no need to await, returns to the UI thread to continue execution
DoSomethingElse();//Doesn't return to the UI thread to continue execution
DoSomethingElse().???(); // how to return to the UI thread for the async callback?
}
In F# this would look like this:
let CallDoSomething () =
//more code here
async {
//runs on the current thread
do! OtherThing()
//runs on the current thread
} |> Async.StartImmediate
//code here doesn't wait for the async to finish
So, when looking at your code example. You have an async method that return a Task. You're calling that method, and then calling Start on the resulting task (without calling await). That will throw an exception at runtime. The task is already started just by calling the method. Starting an already running task (or a completed task, if it completed before it returned) will throw an exception. You can only Start a task created using the Task constructor, which you're not using.
You also claim, in comments, that you are not in the UI thread when you return after calling DoSomethingElse. That is false. The code will run in the UI thread.
You also imply that the await in DoSomethingElse won't marshal the callback to the UI thread, but it will. Since it was called from the UI thread, it captured the UI context, and uses it when calling await.
So in short, you need to do nothing except remove the call to Start.
The one problem you do have, if you structure your code like this, is that you will never know if your code errors out, as there is nothing to observe any exceptions. There are two ways you could address this. One would be for each of the methods you call in this manor to consider themselves "top level methods" and handle all exceptions instead of every throwing any.
The other option would be to store all of the tasks called in this manner and await Task.WhenAll those tasks, so you can observe any errors when they all finish.
Did you try the RunSynchronously() method of the Task class ?