Why:ThreadPool沒有內建機制標記當前線程在什么時候完成,也沒有機制在操作完成時獲得返回值,因而推出了Task,更精確的管理異步線程。
How:通過構造方法的參數TaskCreationOptions控制如何創建任務,具體查看該枚舉的枚舉值。獲取任務執行的結果有Task.Result屬性,該屬性內部調用wait(),例如WaitAny()、WaitAll()等等都可以。
如何取消異步計算限制操作呢?也就是說如何取消執行中的任務呢?(鄙視clr的作者用“計算限制操作”這么復雜的詞匯。)
實例化CancelletionTokenSource類,把該對象作為參數傳給異步方法,在異步方法中調用該對象的ThrowIfCancellationRequested(),如果該對象的Cancel()方法被調用了,那么異步方法就會拋出異常OperationCanceledException,在主線程用try-catch進行捕獲(AggregateException),就可以捕獲異常並進行處理。
class Program
{
static void Main(string[] args) { CancellationTokenSource cts = new CancellationTokenSource();//CancellationTokenSource(3000);//3秒后沒有得到結果,則取消該線程。 Task<Int32> t1 = Task.Run(() => sum(cts.Token, 10000), cts.Token);//傳入CancellationToken,它是CancellationTokenSource的屬性。 cts.Cancel();//cts.CancelAfter(3000);//3秒后如果沒有得到結果,則取消該線程。 try { Console.WriteLine("t1執行的結果是:" + t1.Result);//通過Result獲取t1的執行結果。 } catch (AggregateException ex) { ex.Handle(e => e is OperationCanceledException); Console.WriteLine("sum已經被取消"); } Console.ReadKey(); } private static int sum(CancellationToken ct, int p) { int sum = 0; while (p > 0) { ct.ThrowIfCancellationRequested(); Thread.Sleep(500);//每隔半秒累加一次。 checked//如果區域內的計算溢出就會拋出異常 { sum += p; } p--; } return sum; } }
運行結果:sum已經被取消
成功的捕獲到了異常並處理了。
但是我發現有一個地方我不能理解
1、如果是通過CancellationTokenSource的構造方法public CancellationTokenSource(int millisecondsDelay);構造的實例對象,try-catch捕獲不到異常。
2、如果是通過CanelAfter(TimeSpan delay)取消,也捕獲不到異常。
通過ILSpy我發現上訴構造方法和CanelAfter方法都是調用Cancel()方法,但是為何捕獲不到異常呢?
我進一步查看ThrowIfCancellationRequested源碼
public void ThrowIfCancellationRequested()
{
if (this.IsCancellationRequested) { this.ThrowOperationCanceledException(); } }
然而並沒有什么卵用,因為只要把下圖中的設置取消,即可捕獲到了異常。