I've read about asynchronous programming in C#, but I still do not fully understand how continuation of async method is executed.
From my understanding, Asynchronous programming is not about multithreading. We can run async method on UI Thread, and it later continues on that UI Thread (while not blocking and continuing to respond to other messages from message loop).
This is basic message loop most GUI apps have:
while (1)
{
bRet = GetMessage(&msg, NULL, 0, 0);
if (bRet > 0) // (bRet > 0 indicates a message that must be processed.)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
...
DispatchMessage() calls UI event handlers. And the code inside the event handlers should not block the main thread. For that reason if we want to, i.e. create a button that loads a heavy data from disk, we can use async method like this: (simplified pseudo code)
public async Task ButtonClicked()
{
loadingBar.Show();
await AsyncLoadData();
loadingBar.Hide();
}
When execution reaches await AsyncLoadData(); line, it stores the context and returns the Task object. DispatchMessage() finishes and message loop repeatedly comes to the bRet = GetMessage(&msg, NULL, 0, 0); line.
So my question is, how the rest code is executed? Is finished async operation triggers a new message, that is then handled by DispatchMessage() again? Or the message loop has another method (after dispatch), that checks for finished async operations?
So my question is, how the rest code is executed? Is finished async operation triggers a new message, that is then handled by DispatchMessage() again? Or the message loop has another method (after dispatch), that checks for finished async operations?
await by default will capture a "context" and use that to resume the execution of the method. This "context" is SynchronizationContext.Current, falling back on TaskScheduler.Current. UI apps provide a SynchronizationContext, e.g., WindowsFormsSynchronizationContext or DispatcherSynchronizationContext. When the await completes, it schedules the continuation of the method onto that context (in this case, onto the SynchronizationContext).
For WinForms, the syncctx uses Control.BeginInvoke, which will post a Win32 message which is handled by the WinProc.
For WPF, the syncctx posts to its Dispatcher, which adds the callback to the dispatch queue. This queue is also processed by a Win32 WinProc loop.
Alex Davies wrote an excellent book on this, it is called "Async in C# 5", I strongly recommend reading it.
I can't tell low level details behind this, but at the high level CLR will create something like this:
void __buttoncliked_remaining_code_1(...) {
loadingBar.Hide();
}
So, a specific event will be triggered indicating that async job has completed.
Then __buttoncliked_remaining_code_1() will be executed, sinchronously, just like any regular C# function.
CLR will use for that any thread, but most likely it will reuse the one that encountered await keyword, which in your case might be GUI thread.
Related
Say in button click event I have:
await someFn()
And in the someFn code, I have got some synchronous code and some asynchronous code.
As per online reading on this topic, they all seem to say that when await is encountered, control immediately goes back the caller (UI thread in this case) while the asynchronous waiting happens.
I haven't come across situation where it is explained what happens when there is some synchronous code just before the async code in the awaited function. Does the synchronous code execute before passing the control to the caller (UI thread)?
I know that- had it been run using await Task.Run(...) instead of await someFn() then it would execute in a separate thread.
It is true that "when await is encountered, control immediately goes back the caller", under the condition that the awaitable will not be completed at the await point. Otherwise (if the awaitable is already completed) the control will stay inside the method, by executing immediately the code that follows the await.
That's all that influences the behavior of the await operator: the result of the IsCompleted property of the awaiter. It doesn't matter if the method that produced the awaitable included synchronous code or not. The await doesn't know, and doesn't care. A synchronous code block inside the someFn will indeed make a difference regarding the responsiveness of your application, but that has nothing to do with the await. To understand why, it may help to rewrite your code in a more verbose but equivalent form. This:
await someFn();
...is equivalent to this:
Task t = someFn();
await t;
The UI of your application will freeze because the someFn() blocks, not because the await t blocks. Unless of course you have created some wicked task-like awaitable type, that blocks when the IsCompleted property of its awaiter is invoked.
If you see an await in your code, for example when you see var obj = await someFn();, then you can treat is as a placeholder for the following code:
var waitingTask task = someFn();
if (!task.IsCompleted) {
var thisTask = [Magic]
return thisTask.Task;
}
var obj = waitingTask.Result;
In reality the code is rewritten to something more complex, a so called state machine. The [Magic] part is hard to explain but what it does is capturing the current SynchronizationContext, the current line that is executing and the task it's waiting on.
As soon as the task that you are waiting on completes, it will try to restore this method on the captured SynchronizationContext and continue working. It's this SynchronizationContext that tells you if you are working on the UI thread or not. This is why it's advised to use ConfigureAwait(false) to avoid restoring on the UI thread if it's not needed, avoiding possible slow downs on the UI for executing code that does nothing with the UI.
The main point here is that you see that the code before an await is executed synchronously/immediately. Even the code inside the function that you are calling is executed synchronously/immediately until you reach an await in that function that is not completed. From this point on the stack 'rewinds', creating (returning) a new Task on each point that waits for the underlying code to complete. If the lowest task completes, only that task that waits for it is 'revived', all tasks above it still stay 'waiting' and only when that bottom function has reached it real end of the method will it 'revive' the task that is waiting for it's result, and so on to the top of the stack.
I'm having trouble understanding what runs on the main thread during an async await operation and would be grateful for some answers.
Let's say I have a button that is supposed to log the user in.
it is supposed to block all other user input while the login process transpires, show a progress view and then when the result comes in display it
and here is the method that performs the log in
button_clicked(object sender, EventArgs e) {
do_login(); //I do not await the result
do_some_other_stuff(); //this doesn't actually exist I just put it here to ask my questions
}
async Task do_login() {
string user_name = txtUser.Text;
string password = txtPassword.Text;
show_progress(true); //this is not an async method;
string error = await _login.do_login(user_name, password);//this is an async method that can take up to 20 seconds to complete;
show_progress(false);
if (error != null) {
show_error(error);
} else {
show_next_screen();
}
}
I have two questions on the above example
a) What will be run on the main thread?
If I understand it correctly only _login.do_login will be run on a seperate thread, all others will be on the main thread, is this correct?
b) In what order will the methods be executed?
Again if I understand it correctly, it will be :
do_login()
show_progress(true);
_login.do_login starts;
do_some_other_stuff();
_login.do_login finishes;
show_progress(false);
and it will continue from there
is this correct? if not, how can I achieve such a behaviour?
c) If my code above is correct then why do I keep receiving a warning that do_login() is not awaited? I do not wish to await it I just want it to run what it can and return when it wants, should I ignore that warning?
Technically, depending on the implementation of do_login, everything could run in the main thread. In this case I assume you're contacting a web server, so that part won't, but this is not always true. And asynchronous operation does not necessarily executes in another thread. One operation is asynchronous when:
It doesn't block the calling thread.
Usually, UI threads run an 'event loop'. So an asynchronous task could simply put a new piece of work into the event queue to be executed whenever the scheduler determines, but in the same thread. In this case you don't use two threads, but still, you don't have to wait for the task to complete and you don't know when it'll finish.
To be precise, all the code in your post will run in the main thread. Only the part in do_login that manages the connection with the server, waiting and retrieving data will execute asynchronously.
You're mostly right about the sequence, with a few adjustments:
do_login() (until the await)
login._do_login() starts executing
do_some_other_stuff()
...
login.do_login finishes
show_progress()
The answer to your main question is: it depends. The _login.do_login method will likely be put onto its own thread, but it actually depends on the .NET task scheduler. In WPF and ASP.NET it will be scheduled onto the thread pool if it doesn't immediately return a completed task.
The important part is that you know it will not block execution of the calling (in your case, the main) thread. Your understanding of the method flow is correct since you don't await do_login.
As far as the warning goes; you can mark do_login as async void to avoid it, though generally you only do that for event handlers which can then await a Task returning method. If you do go the async void route; make sure to put a try/catch in as such methods will throw all the way up to the root handler and can cause your app to crash.
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.
Background:
I have a "Messenger" class. It sends messages. But due to limitations, let's say it can only send - at most - 5 messages at a time.
I have a WPF application which queues messages as needed, and waits for the queued message to be handled before continuing. Due to the asynchronous nature of the application, any number of messages could be awaited at any given time.
Current Implementation:
To accomplish this, I've implemented a Task<Result> SendMessage(Message message) API within my messaging class. Internal to the messaging class is a custom TaskScheduler (the LimitedConcurrencyTaskScheduler from MSDN), with its concurrency level set to 5. In this way, I would expect that no matter how many messages are queued, only 5 will be sent out at a time, and my client application will patiently wait until its respective message has been handled.
Problem:
When I await the SendMessage method, I can see via the debugger that the message was completed and the result returned, but my code never executes beyond the awaited method call!
Is there some special considerations that need to be made, when awaiting a Task which was scheduled using a different TaskScheduler?
Snipped Code:
From my client/consuming function:
public async Task Frobulate()
{
Message myMessage = new Message(x, y, z);
await messenger.SendMessage(myMessage);
//Code down here never executes!
}
From my messenger class:
private TaskScheduler _messengerTaskScheduler = new LimitedConcurrencyLevelTaskScheduler(5);
private TaskFactory _messengerTaskFactory = new TaskFactory(_messengerScheduler);
public Task<Result> SendMessage(Message message)
{
//My debugger has verified that "InternalSendMessage" has completed,
//but the caller's continuation appears to never execute
return _messengerTaskFactory.StartNew(() => InternalSendMessage(message));
}
Update:
The 'freeze' does not actually appear to be caused by my custom TaskScheduler; when I queue up the Task with the default TaskFactory, the same behavior occurs! There must be something else happening at a more fundamental level, likely due to my own stupidity.
Based on the comments, you probably have a deadlock because you're blocking on async code.
When using async, whenever there are thread restrictions on the SynchronizationContext or TaskScheduler and the code blocks using Task.Result or Task.Wait there's a possibility of deadlocking. The asynchronous operation needs a thread to finish execution, which it can't get because the SynchronizationContext (or TaskScheduler in your case) is waiting for that same exact operation to complete before allowing "new" ones to run.
Go deeper in Stephen Cleary's blog post: Don't Block on Async Code
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.