Task.Factory.StartNewTResult 和 Task.RunTResult 到底有什么区别?
前言
這不是和《Task.Factory.StartNew 和 Task.Run 到底有什么區別?》一樣嗎,怎么又寫一篇?
起先我也是這么覺得的,但實際發現并非如此。
實現代碼
查看這 2 個方法的內部實現,其內部實現邏輯其實是一樣的,只是傳的默認參數不同:
//Task.Factory.StartNew<TResult> public?Task<TResult>?StartNew<TResult>(Func<TResult>?function) {Task??currTask?=?Task.InternalCurrent;return?Task<TResult>.StartNew(currTask,?function,?m_defaultCancellationToken,m_defaultCreationOptions,?InternalTaskOptions.None,?GetDefaultScheduler(currTask)); }//Task.Run<TResult> public?static?Task<TResult>?Run<TResult>(Func<TResult>?function) {return?Task<TResult>.StartNew(null,?function,?default,TaskCreationOptions.DenyChildAttach,?InternalTaskOptions.None,?TaskScheduler.Default); }這不還和上次一樣嗎?
Demo
讓我們創建代碼驗證一下:
Stopwatch?stopwatch1?=?new?Stopwatch(); stopwatch1.Start(); var?task1?=?Task.Factory.StartNew(async?()?=> {await?Task.Delay(1000);return?"Task.Factory.StartNew"; });Console.WriteLine(await?task1); stopwatch1.Stop(); Console.WriteLine(stopwatch1.ElapsedMilliseconds);Stopwatch?stopwatch2?=?new?Stopwatch(); stopwatch2.Start(); stopwatch2.Start(); var?task2?=?Task.Run(async?()?=> {await?Task.Delay(1000);return?"Task.Run"; });Console.WriteLine(await?task2); stopwatch2.Stop(); Console.WriteLine(stopwatch2.ElapsedMilliseconds);運行程序,你將會看到類似的如下輸出:
System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1+AsyncStateMachineBox`1[System.String,ConsoleApp1.Program+<>c+<<Main>b__0_0>d] 86 Task.Run 1024是不是很你想的結果完全不一樣!
使用 Task.Factory.StartNew<TResult> 的返回并不是 Task<string>,而是Task<Task<string>>:
這是為什么呢?
原理
其實是因為上述代碼傳入的參數類型不是 Func<TResult> 而是 Func<Task<TResult>?>,而 Task.Run<Task<TResult>?>?對此做了一層封裝:
public?static?Task<TResult>?Run<TResult>(Func<Task<TResult>?>?function,?CancellationToken?cancellationToken) {...Task<Task<TResult>?>?task1?=?Task<Task<TResult>?>.Factory.StartNew(function,?cancellationToken,?TaskCreationOptions.DenyChildAttach,?TaskScheduler.Default);UnwrapPromise<TResult>?promise?=?new?UnwrapPromise<TResult>(task1,?lookForOce:?true);return?promise; }內部同樣使用 Task.Factory.StartNew<Task<TResult>?> 生成任務,但是返回的是 UnwrapPromise<TResult>:
//?This?class?encapsulates?all?"unwrap"?logic,?and?also?implements?ITaskCompletionAction, //?which?minimizes?the?allocations?needed?for?queuing?it?to?its?antecedent.??This //?logic?is?used?by?both?the?Unwrap?extension?methods?and?the?unwrap-style?Task.Run?methods. internal?sealed?class?UnwrapPromise<TResult>?:?Task<TResult>,?ITaskCompletionAction而 Task.Factory.StartNew<TResult> 沒有這層封裝。
不過,要想Task.Factory.StartNew<TResult>達到Task.Run<TResult>同樣目的,可以使用 Unwrap 方法:
public?static?Task<TResult>?Unwrap<TResult>(this?Task<Task<TResult>>?task!!)?=>//?If?the?task?hasn't?completed?or?was?faulted/canceled,?wrap?it?in?an?unwrap?promise.?Otherwise,//?it?completed?successfully.??Return?its?inner?task?to?avoid?unnecessary?wrapping,?or?if?the?inner//?task?is?null,?return?a?canceled?task?to?match?the?same?semantics?as?CreateUnwrapPromise.!task.IsCompletedSuccessfully???Task.CreateUnwrapPromise<TResult>(task,?lookForOce:?false)?:task.Result???Task.FromCanceled<TResult>(new?CancellationToken(true));//使用示例 var?task1?=?Task.Factory.StartNew(async?()?=> {await?Task.Delay(1000);return?"Task.Factory.StartNew"; });Console.WriteLine(await?task1.Unwrap());結論
在使用 Task.Factory.StartNew 時,如果需要等待內部任務的最終完成,需要使用 Unwrap 方法進行“解開”。
想了解更多內容,請關注我的個人公眾號”My IO“
總結
以上是生活随笔為你收集整理的Task.Factory.StartNewTResult 和 Task.RunTResult 到底有什么区别?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【鉴权/授权】一步一步实现一个简易JWT
- 下一篇: 分享一个基于.NET6包含DDD,ES,