Task.Run 和 Task.Factory.StartNew 都可以把一段要執行的代碼放到ThreadPool thread中去執行。Task.Factory.StartNew是.Net 4.0中引入的,而Task.Run則是在.Net 4.5中引入,首要目的是為了簡化Task.Factory.StartNew的使用。簡言之,
Task.Run(someAction)
與
Task.Factory.StartNew(someAction, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
是基本等價的。
說基本等價,是因為這兩種用法還是有不完全相同的地方。
比如下面的代碼
var t = Task.Factory.StartNew(delegate { return 42; });
通過Task.Factory.StartNew ,我們把一個TResult是int的delegate變成了Task<int>類型。
那么下面的代碼呢
var t = Task.Factory.StartNew(async delegate { await Task.Delay(1000); return 42; });
傳給Task.Factory.StartNew的是一個asyn的delegate,即是Task<int>類型。通過Task.Factory.StartNew,得到的t是一個Task<Task<int>>類型。
這時候,如果我們await t,實際上,當它返回時,並不是這個async的delegate執行完成了,而是得到了Task<int>。這通常不是我們想要的結果。
為了處理這種情況,.Net 4引入了Unwrap函數。Unwrap有兩個重載方法,一個是作用於類型Task<Task>上,另外一個是作用於Task<Task<TResult>>上。
在Task<Task>上調用Unwrap會返回一個新的Task,它代表這內部Task最終是否完成。
回到前面的例子,如果我想讓t代表內部的async delegate,那么可以這樣
var t = Task.Factory.StartNew(async delegate { await Task.Delay(1000); return 42; }).Unwrap();
接下來講Task.Run。由於上面所述的用法是一種很常見的需求,因此在.Net 4.5中,
var t = Task.Run(async delegate { await Task.Delay(1000); return 42; });
上述代碼就直接得到的是Task<int>,而不是Task<Task<int>>。
即該代碼等價於
var t = Task.Factory.StartNew(async delegate { await Task.Delay(1000); return 42; }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap();