. NET (C #): Task.unwrap extension methods and async Lambda
Directory
- Task.unwrap Basic Use
- Unwrap operation of Task.Factory.StartNew and Task.run
- Use case: Async LAMBDA in LINQ
Back to CatalogTask.unwrap Basic Use
This extension method is defined in the Taskextensions type, and the namespace is System.Threading.Tasks. Unwrap will extract the results of nested task<task> or task<task<t>>.
Like this, without unwrap words:
staticvoid Main (string[] args)
{
Doo ();
Task.delay (-1). Wait ();
}
staticasyncvoid Doo ()
{
//Run nested task
//task return task<task<string>>
///The result type is task<string> after the first await
var result =awaittask.run<task<string>> (() =
{
var task =task.run<string> (() =
{
Task.delay (1000). Wait ();
return "MGen";
});
return task;
});
///second await before returning a string
Console.WriteLine (await result);
}
With unwrap, the results can be extracted directly from the nested task:
staticasyncvoid Doo ()
{
//Run nested task
//task return task<task<string>>
//await After type is task<string>,unwrap, result type is String
var result =awaittask.run<task<string>> (() =
{
var task =task.run<string> (() =
{
Task.delay (1000). Wait ();
return "MGen";
});
return task;
}). Unwrap ();
//Do not need Await,result is already a string
Console.WriteLine (result);
}
Back to Catalogunwrap operation of Task.Factory.StartNew and Task.run
Simply speaking, One of the differences between Task.Factory.StartNew and Task.run is that Task.run will automatically perform unwrap operations, but Task.Factory.StartNew will not, Task.run is Task.Factory.StartNew more humane seal The Task.Factory.StartNew is the original execution. (in addition, for more differences, a highly-rated article from the PFX team is recommended:Task.run vs Task.Factory.StartNew).
To verify by code:
var task1 =task.factory.startnew (Async () = "MGen");
var task2 =task.run (Async () = "MGen");
Console.WriteLine (Task1. GetType ());
Console.WriteLine (Task2. GetType ());
Output:
System.Threading.Tasks.Task ' 1[system.threading.tasks.task ' 1[system.string]
System.Threading.Tasks.UnwrapPromise ' 1[system.string]
Can see
Using Task.Factory.StartNew will return the original task<task<string>>. However, Task.run will return the result of the async lambda directly, and the middle unwrap operation will be performed automatically.
Back to Cataloguse case: Async LAMBDA in LINQ
The article tells here, perhaps the reader is thinking that this situation will not be very rare to see? No, any use of async lambda can occur, such as a recent WINRT project, using LINQ to transform some data, but many WINRT APIs are executed asynchronously, and such problems arise, as shown in the following example:
Let's do a simple LINQ select operation that converts a bunch of int into a string, except that the conversion process is asynchronous and looks at the code:
staticvoid Main (string[] args)
{
Doo ();
Task.delay (-1). Wait ();
}
staticvoid Doo ()
{
//int Data
var ints =enumerable.range (1, ten);
//Convert and output results
foreach (Var str in ints. Select (Async i =>await int2stringasync (i)))
Console.WriteLine (str);
}
//asynchronously converts int to string
staticasynctask<string> int2stringasync (int i)
{
returnawaittask.run<string> (() = i.ToString ());
}
Is the above code correct? A lot of people will think it's okay, the Select method invokes the asynchronous transform method with an async lambda and waits for the result asynchronously, and then the async lambda returns the String,str type as a string, and the last output is the string.
But in fact the program will output after running:
System.Threading.Tasks.Task ' 1[system.string]
System.Threading.Tasks.Task ' 1[system.string]
System.Threading.Tasks.Task ' 1[system.string]
System.Threading.Tasks.Task ' 1[system.string]
System.Threading.Tasks.Task ' 1[system.string]
System.Threading.Tasks.Task ' 1[system.string]
System.Threading.Tasks.Task ' 1[system.string]
System.Threading.Tasks.Task ' 1[system.string]
System.Threading.Tasks.Task ' 1[system.string]
System.Threading.Tasks.Task ' 1[system.string]
The STR variable is not a string at all, but task<string>. The above inference is wrong (the yellow notation above) "Async lambda Returns string", the result of async lambda is not await, the above await is just an asynchronous wait for the Int2stringasync method, and Async The lambda itself still returns TASK<STRING>, so select returns the task<string> of some columns.
The simplest solution is to add an await when processing the results, as follows:
The type of STR is actually:task<string>
Console.WriteLine (str);
This is the best way (if you can), because with this await, the whole conversion process is actually asynchronous!
Of course, if you want to return the result string in LINQ select directly instead of TASK<STRING>:
Then there is a solution that does not use async Lambda, there is no problem of nested tasks, directly in select returns the task's result property of the Async method:
int data
var ints =enumerable.range (1, 10);
Select Calls Async method
Ienumerable<string> STRs = ints. Select (i = Int2stringasync (i). Result);
If you must use Async LAMBDA, you must unwrap the nested task. (Of course, there is more to discuss the technology itself, the actual work is not necessary to such a dead-looking. )
In conjunction with the above mentioned knowledge, using Task.Factory.StartNew requires a unwrap, and then returns the result of task<t> as the final return value of the Select method, code:
int data
var ints =enumerable.range (1, 10);
Select Calls Async method
Ienumerable<string> STRs = ints. Select (i =
Task.Factory.StartNew (Async () =>await int2stringasync (i)). Unwrap (). Result);
and task.run words, do not need unwrap:
Ienumerable<string> STRs = ints. Select (i =
Task.run (Async () =>await int2stringasync (i)). Result);
Transfer from Http://www.mgenware.com/blog/?p=338#_hContent
"Reprinted". NET (C #): Task.unwrap extension method and Async Lambda