Task. Run and Task. Factory. StartNew, taskfactory. startnew
In. Net 4Medium,Task.Factory.StartNew
Is to start a newTask
. It has many overload methods, so that it can be very flexible in use. By setting optional parameters, you can pass in any State, cancel the task to continue execution, or even control the scheduling behavior of the task. All these capabilities also increase complexity. You must know when to use the overload method and what scheduling method to provide. AndTask.Factory.StartNew
This method is not concise and clear. At least it is not fast enough to use the main scenario. Generally, the main scenario is to throw a job to a background thread for execution.
Therefore. NET Framework 4.5 Developer Preview, Microsoft introduced a newTask.Run
Method. The new method is not used to replace the old one.Task.Factory.StartNew
Method, but provides a way to useTask.Factory.StartNew
Method, rather than specifying the series of parameters. This is a shortcut. In fact,Task.Run
Internal implementation logic andTask.Factory.StartNew
Similarly, some default parameters are passed. For example, when you useTask.Run
:
Task.Run(someAction);
In fact, it is equivalent:
Task.Factory.StartNew(someAction, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
Use these default parameters,Task.Run
It can be used in most cases-simply hand the task to the background thread pool for execution (this is also used)TaskScheduler.Default
Parameter ). This does not meanTask.Factory.StartNew
The method does not need to be used any more. It still has many important functions. You can controlTaskCreationOptions
Parameters to control the actions of a task, you can also controlTaskScheduler
To control how tasks should be queued and run, you can also use the parameter that accepts the object status in the overload method. For some performance-sensitive code, it can be used to avoid closures and corresponding resource allocation. However, for the simple example above,Task.Run
Is the most friendly.
Task.Run
Eight overload methods are provided to provide the following combinations:
The first two are obvious.Task
If the overload method of the returned value is used, the task does not return the value.Task<TResult>
If you do the return value overload method, the task has a typeTResult
. The second point is also accepted.CancellationToken
You can run the cancel operation before the Task starts, and then the Parallel Task (Task Parallel Library -- TPL) can naturally overload to the canceled state.
The third point is more interesting. It is directly related to the asynchronous language support of C # and Visual Basic in Visual studio 11. UseTask.Factory.StartNew
To show this problem, if you have the following code:
var t = Task.Factory.StartNew(() => { Task inner = Task.Factory.StartNew(() => {}); return inner; });
Heret
Is inferredTask<Task>
Because the task delegate type isFunc<TResult>
So hereTResult
IsTask
, SoStartNew
Method returnsTask<Task>
, Similarly, I can change it to the following method:
var t = Task.Factory.StartNew(() => { Task<int> inner = Task.Factory.StartNew(() => 42)); return inner; });
Heret
The type isTask<Task<int>>
, Whether the task delegate type isFunc<TResult>
,TResult
IsTask<int>
,StartNew
Method returnsTask<Task<int>>
. What is the relationship between them? Consider the following method if we use it:
var t = Task.Factory.StartNew(async delegate { await Task.Delay(1000); return 42; });
Used hereasync
Keyword, the compiler maps this delegateFunc<Task<int>>
, Calling this delegate will eventually returnTask<int>
. Because this delegate isFunc<Task<int>>
,TResult
IsTask<int>
, So the lastt
The typeTask<Task<int>>
InsteadTask<int>
.
To cope with these situations. Net 4Introduced inUnwrap
Method.Unwrap
There are two methods for overloading, both of which are extension methods andTask<Task>
, The other is<Task<TResult>>
. Microsoft only needs to name this method Unwrap because it can return the actual results of the task. PairTask<Task>
CallUnwrap
Method returns a newTask
(Like a proxy for an internal task) represents its internal task. SimilarTask<Task<TResult>>
CallUnwrap
Returns a newTask<TResult>
It represents its internal tasks. However, if an external task fails or is canceled, there will be no internal task. Because no task is completed, the proxy task becomes the status of the external task. Return to the previous example.t
It indicates the return value of an internal task (in this example, the value is 42), so it should be written as follows:
var t = Task.Factory.StartNew(async delegate { await Task.Delay(1000); return 42; }).Unwrap();
Now, the variablet
IsTask<int>
Indicates the result of an asynchronous call.
Now returnTask.Run
Because Microsoft wants developers to use this method to enable background tasks as much as possible, and can workasync/await
So Microsoft decidedTask.Run
Built-in Methodsunwrapping
. This is also the content mentioned in the third point above,Task.Run
Is acceptable in the overload methodAction
(Tasks with no returned values), acceptedFunc<TResult>
(ReturnTResult
Yes.Func<Task>
(Return the task of an asynchronous task), and acceptFunc<Task<TResult>>
(ReturnsTResult
Type returned value of the asynchronous task. In general,Task.Run
The method provides the aboveTask.Factory.StartNew
Same Methodunwrapping
Operation. Therefore, we can write as follows:
var t = Task.Run(async delegate { await Task.Delay(1000); return 42; });
t
IsTask<int>
, HereTask.Run
The reload method is equivalent:
var t = Task.Factory.StartNew(async delegate { await Task.Delay(1000); return 42; }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap();
As mentioned above, this is a shortcut.
All the class content mentioned above means that you can useTask.Run
Call Standardlambdas/anonymous
Method or asynchronouslambdas/anonymous
Method, always run according to your expected behavior. If you want the task to run in the background and wait for its results, you can write it as follows:
int result = await Task.Run(async () => { await Task.Delay(1000); return 42; });
Variableresult
Is exactly what you expectedint
And after the task is called for about one second, the variableresult
Is set to 42.
Interestingly, the newawait
Keyword is considered to be equivalentUnwrap
A new syntax form of the method. So, if we go back toTask.Factory.StartNew
For example, we can useUnwrap
Rewrite the code snippet above:
int result = await Task.Factory.StartNew(async delegate { await Task.Delay(1000); return 42; }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap();
Alternatively, you can use the secondawait
ReplaceUnwrap
:
int result = await await Task.Factory.StartNew(async delegate { await Task.Delay(1000); return 42; }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
Hereawait await
Although it looks awkward, there is no problem.Task.Factory.StartNew
Method returnsTask<Task<int>>
Task<Task<int>>
Useawait
Actually returnTask<int>
And thenTask<int>
Useawait
Last returnint
Isn't that true?