As we all know, the async method can only return void, Task, and Task <T>.
For the async method that returns void, it is not awaitable, so other methods cannot call it using the await method, but the async method that returns the Task can.
So when the async method returns a Task and await goes on, What is the concept of a Task that is await? Is the first Task in the async method await? No, it indicates the full execution of the target async method, including the connected tasks separated by await, but not the multi-thread execution caused by non-await.
The following code: In doo, it is an async method that returns the Task, and await calls doo in the test method, and then calls test in the Main method (because the Main method does not allow async, so we need to add another async method to use await)
Static void Main (string [] args)
{
Test ();
Log ("Main: After test is called ");
Thread. Sleep (Timeout. Infinite );
}
// Async is not allowed for the Main method, so we use await in this method.
Static async void test ()
{
Log ("test: Before await ");
Await doo ();
Log ("test: After await ");
}
// Return The async method of the Task
Static async Task doo ()
{
Log ("doo: Task Result:" + await Task. run () => {Thread. sleep (1000); log ("Task"); return 1 ;}));
Log ("doo: Task Result:" + await Task. run () => {Thread. sleep (1000); log ("Task"); return 2 ;}));
Log ("doo: Task Result:" + await Task. run () => {Thread. sleep (1000); log ("Task"); return 3 ;}));
Thread. Sleep (1000 );
Console. WriteLine ("the Thread. Sleep in doo is executed out of Task ");
}
// Output method: display the ManagedThreadId of the current thread
Static void log (string msg)
{
Console. WriteLine ("{0 }:{ 1}", Thread. CurrentThread. ManagedThreadId, msg );
}
The above code will output:
1: test: Before await
1: Main: After test is called
3: Task
3: doo: Task result: 1
4: Task
4: doo: Task result: 2
3: Task
3: doo: Task result: 3
Thread. Sleep out of Task in doo is finished.
3: test: After await
The first two sentences are simple. Call the test method. The content after await will be added to the end of the target Task, and test will return immediately, so the output "Main: after the test is called" is displayed ", at the same time, they are all executed in the main thread, so ManagedThreadId is 1.
The next step is the execution of another Task (of course, in another thread, it is also the target Task of await in the test method ). This so-called Task is the full execution of the doo method. Therefore, tasks executed in three sequence in doo (connected one by one through await) are executed in sequence. Therefore, the Task outputs results 1, 2, and 3. The ManagedThreadId of the first Task is 3, the second is 4, and the third is 3, because the internal execution of the Task uses the CLR thread pool, so the thread is reused.
The doo method is not complete yet. The code behind the doo method is executed after the last await Task is executed. Therefore, the Thread outside the Task in doo is output. sleep execution is complete.
Finally, after doo executes test await completely, the result is output in the last line: test: await.
As I said above: the tasks returned by the await async method represent "All execution of the target async method, including connection tasks separated by await, but not multi-thread execution caused by non-await ".
Therefore, if you change the async method of the returned Task (that is, the doo method in the previous example) to the following:
// Return The async method of the Task
Static async Task doo ()
{
Log ("doo: Task Result:" + await Task. run () => {Thread. sleep (1000); log ("Task"); return 1 ;}));
Log ("doo: Task Result:" + await Task. run () => {Thread. sleep (1000); log ("Task"); return 2 ;}));
Log ("doo: Task Result:" + await Task. run () => {Thread. sleep (1000); log ("Task"); return 3 ;}));
// Do not use await: multi-thread Thread Pool
ThreadPool. QueueUserWorkItem (_ =>
{
Thread. Sleep (1000 );
Console. WriteLine ("ThreadPool. QueueUserWorkItem ");
});
// Do not use await: multi-thread Task
Task. Run () =>
{
Thread. Sleep (1000 );
Console. WriteLine ("Task. Run ");
});
}
We have added multi-thread execution without await, respectively using ThreadPool and Task. The entire program will output the following results:
1: test: Before await
1: Main: After test is called
3: Task
3: doo: Task result: 1
4: Task
4: doo: Task result: 2
3: Task
3: doo: Task result: 3
3: test: After await
Task. Run
ThreadPool. QueueUserWorkItem
Multithreading without await completely disconnects from await tasks in the test method, and runs after await of test.
In addition, Visual Studio will give the following warning to the Task. Run code:
Tip: Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.
That is to say, if await is not added, the current method will continue to be executed until the end, because we are currently doing a test in the async method without await, huh, huh. Www.2cto.com
You may ask, why do you want to use this method to return tasks from another async method of await? We have been discussing the async Method for returning tasks. I think the async Method for returning tasks <T> can better explain this problem.
Next we will change the above Code to a similar async method that returns the Task <int> for execution, then the doo method returns the Task <T>, he sums up the results of the three awaited tasks in his method and returns the results as the results of the Task returned by him. Then output the results returned by doo in the test method.
Complete code:
Static void Main (string [] args)
{
Test ();
Log ("Main: After test is called ");
Thread. Sleep (Timeout. Infinite );
}
// Async is not allowed for the Main method, so we use await in this method.
Static async void test ()
{
Log ("test: Before await ");
Console. WriteLine ("doo result: {0}", await doo ());
Log ("test: After await ");
}
// Return The async method of the Task
Static async Task <int> doo ()
{
Var res1 = await Task. Run () => {Thread. Sleep (1000); log ("awaited Task1 execution"); return
Var res2 = await Task. Run () => {Thread. Sleep (1000); log ("awaited Task2 execution"); return
Var res3 = await Task. Run () => {Thread. Sleep (1000); log ("awaited Task3 execution"); return
// Do not use await: multi-thread Thread Pool
ThreadPool. QueueUserWorkItem (_ =>
{
Thread. Sleep (1000 );
Console. WriteLine ("ThreadPool. QueueUserWorkItem ");
});
// Do not use await: multi-thread Task
Task. Run () =>
{
Thread. Sleep (1000 );
Console. WriteLine ("Task. Run ");
});
Return res1 + res2 + res3;
}
// Output method: display the ManagedThreadId of the current thread
Static void log (string msg)
{
Console. WriteLine ("{0 }:{ 1}", Thread. CurrentThread. ManagedThreadId, msg );
}
First look at the results:
1: test: Before await
1: Main: After test is called
3: awaited Task1 execution
4: awaited Task2 execution
4: awaited Task3 execution
Doo result: 6
4: test: After await
ThreadPool. QueueUserWorkItem
Task. Run
Like the previous example of returning a Task, when the await doo method returns a Task in the test method, the awaited Task in doo is first waited, the threads without awaited are not waited. Why? (that is, the question left above )? The following is an example of the returned Task <int>:
In the Task returned by await doo in test, we need the result, and the result is other awaited results included in the method, it can be understood as the subresult of the being. Therefore, your own results require other results. Therefore, you must wait for these results to be returned. Therefore, the results of the await doo method of the test method will also wait for await in all doo, regardless of the multi-thread execution of non-await in other doo (of course, technically speaking, it is impossible, because async/await can rely entirely on the compiler ).
From Mgen