Reputation: 10227
I have questions regarding the execution order of async jobs.
I will ask my question with example because it is easier to be understandable.
It is an official example from https://msdn.microsoft.com/en-us/library/mt674882.aspx with some twist.
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
//async operation:
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
// You can do work here that doesn't rely on the string from GetStringAsync.
DoWork1();
// The await operator suspends AccessTheWebAsync.
string urlContents = await getStringTask;
DoWork2();
return urlContents.Length;
}
Can I say DoWork2
is a callback of client.GetStringAsync
?
If so, DoWork2
is not immediately executed following the completion of client.GetStringAsync
IF DoWork1
runs longer time than client.GetStringAsync
.
Am I right here?
Upvotes: 5
Views: 6316
Reputation: 456887
Yuval's answer is correct.
To answer your followup question:
Is there a way to make the DoWork2 immediately executed once client.GetStringAsync is finished?
Possibly. It depends on the context of this code. It's not possible to have DoWork1
and DoWork2
both running on the UI thread at the same time (obviously, a single thread can only do one thing at a time). But if this is called from a thread pool context, then sure, it's possible to run them both simultaneously.
However, you should shift your thinking from "callback" to "operation". That is, don't think of it as DoWork2
being a "callback" of GetStringAsync
. Instead, think of it like this: I have an operation GetStringAsync
, and I have an operation DoWork2
; I need a new operation that does one and then the other.
Once you shift your thinking this way, the solution is to write a method for the new operation:
async Task<string> GetStringAndDoWork2Async()
{
HttpClient client = new HttpClient();
var result = await client.GetStringAsync("http://msdn.microsoft.com");
DoWork2();
return result;
}
Now you can use that new operation in your higher-level method:
async Task<int> AccessTheWebAsync()
{
var task = GetStringAndDoWork2Async();
DoWork1();
string urlContents = await task;
return urlContents.Length;
}
Upvotes: 6
Reputation: 149558
DoWork2
is not immediately executed following the completion ofclient.GetStringAsync
ifDoWork1
runs longer time thanclient.GetStringAsync
Once you hit that point await client.GetStrinkAsync
, DoWork1()
has already completed, as from your example it looks as it's execution is synchronous. Once client.GetStringAsync
completes, then DoWork2
is set to execute.
The execution flow will be:
GetStringAsync
asynchronously starts. It is executed until it hits it's first internal await
, and then yields control back to AccessTheWebAsync
.DoWork1()
kicks off. As it's synchronous, everyone waits for it's completionclient.GetStringAsync
is asynchronously waited for completion. await
will naturally yield the control of execution to it's caller.client.GetStringAsync
completes, execution will return to AccessTheWebAsync
and DoWork2()
will execute synchronously.urlContents.length
will be returned.Generally, everything after the first await
keyword is set to be the continuation for the rest of the method.
Upvotes: 6