>>返回《C# 併發編程》
html
如今咱們先說明幾個概念:數據庫
Task
和 Task<TResult>
類型實現將來模式,在老式異步編程 API 中,採用回調或事件(event)async
和 await
解決的問題async
方法在開始時以同步方式執行。在 async
方法內部,運行到await
關鍵字會執行一個異步等待
async
方法,並返回,留下一個未完成的 task
。await
住的操做完成,async
方法就恢復運行(不必定是原來的線程,具體看同步上下文的配置)。await
語句等待一個任務完成,這時會捕捉同步上下文。
SynchronizationContext
不爲空,這個上下文就是當前 SynchronizationContext
。SynchronizationContext
爲空,則這個上下文爲當前 TaskScheduler。注意: 最好的作法是,在覈心庫代碼中一直使用
ConfigureAwait
。在外圍的用戶界面代碼中,只在須要時才恢復上下文。編程
Task.Run
await
關鍵字,將任務交給線程池完成,解決讀取時窗體卡頓狀況TaskFactory.StartNew
TaskCompletionSource<T>
。
TaskCompletionSource<T>
。await
拋出的異常,咱們更想要try { await Task.Run(() => throw new NotSupportedException()); } catch (Exception ex) { //print: NotSupportedException Console.WriteLine(ex.GetType().Name); }
Wait()
方法,異常類型被包裝try { Task task = Task.Run(() => throw new NotSupportedException()); task.Wait(); } catch (Exception ex) { //print: AggregateException Console.WriteLine(ex.GetType().Name); }
反面教材: 以前在工做中出現一塊兒事故,實施好的項目,3個月後天天凌晨出現大量設備掉線的狀況。服務器
- 因爲數據超時時間時3個月,並且發現出現問題的日誌和數據清理髮生時間有關聯關係
- 排查代碼發現文件清理器,清理數據使用的Parallel類,並行刪除文件,並且沒有對併發數限制
- 文件清理器運行時,致使服務器性能急劇降低,形成處理設備消息延遲,心跳超時致使掉線
- 重構了文件清理器代碼,解決了這個問題
不保證順序執行。多線程
//ForEach int[] arr = new int[] { 1, 2, 3, 4 }; Parallel.ForEach(arr, item => Console.Write(item)); System.Console.WriteLine(); //PLINQ var sum = arr.AsParallel().Select(item => item * 2).Sum(); System.Console.WriteLine($"sum:{sum}."); //Invoke int num = 10; Parallel.Invoke( () => num += 2, () => num -= 2, () => num -= num, () => num += 2 ); System.Console.WriteLine($"num:{num}."); /* print: 1243 sum:20. num:0. */
系統會把這些異常封裝在 AggregateException 類裏,在程序中拋給代碼。 這一特色對全部方法都是同樣的,包括 Parallel.ForEach、Paralle.lInvoke、Task.Wait 等。 AggregateException 類型有幾個實用的 Flatten 和 Handle 方法,用來簡化錯誤處理的代碼:閉包
try { Parallel.Invoke(() => { throw new Exception(); }, () => { throw new Exception(); }); } catch (AggregateException ex) { ex.Handle(exception => { Console.WriteLine(exception); return true; //「已經處理」 }); }
在編寫任務並行程序時,要格外留意下閉包(closure)捕獲的變量。 記住閉包捕獲的是引用(不是值),所以能夠在結束時以不明顯地方式地分享這些變量。併發
若是事件中帶有參數,那麼最好 採用響應式編程,而不是常規的事件處理程序。異步
//System.Runtime.dll namespace:System 中定義了這些接口 interface IObserver<in T> { void OnNext(T item); void OnCompleted(); void OnError(Exception error); } interface IObservable<out T> { IDisposable Subscribe(IObserver<T> observer); }
Rx(Rx-Main)中定義了響應式編程的封裝,後面會有介紹。async