《C#併發編程經典實例》學習筆記-第一章併發編程概述

併發編程的術語

  • 併發
    同時作多件事情
  • 多線程
    併發的一種形式,它採用多個線程來執行程序。
    多線程是併發的一種形式,但不是惟一的形式。
  • 並行處理
    把正在執行的大量的任務分割成小塊,分配給多個同時運行的線程。
    並行處理是多線程的一種,而多線程是併發的一種。
  • 異步編程
    併發的一種形式,它採用future模式或回調(callback)機制,以免產生沒必要要的線程。
    一個 future(或 promise)類型表明一些即將完成的操做。在 .NET 中,新版 future 類型有 Task 和 Task 。在老式異步編程 API 中,採用回調或事件(event),而不是future。 異步編程的核心理念是異步操做(asynchronous operation):啓動了的操做將會在一段時間後完成。這個操做正在執行時,不會阻塞原來的線程。啓動了這個操做的線程,能夠繼續執行其餘任務。當操做完成時,會通知它的 future,或者調用回調函數,以便讓程序知道操做已經結束。
  • 響應式編程
    一種聲明式的編程模式,程序在該模式中對事件作出響應。
    響應式編程的核心理念是異步事件(asynchronous event):異步事件能夠沒有一個實際的「開始」,能夠在任什麼時候間發生,而且能夠發生屢次,例如用戶輸入。
    若是把一個程序看做一個大型的狀態機,則該程序的行爲即可視爲它對一系列事件作出響應,即每換一個事件,它就更新一次本身的狀態。

異步編程的兩個好處

  1. 對於面向終端用戶的 GUI 程序:異步編程提升了響應能力。面對在運行時被臨時鎖定界面的程序,異步編程可使程序在此時仍能流暢的響應用戶的輸入。譬如:WPF界面,執行一個須要等待的操做時,仍能夠點擊輸入框進行填寫,而不會出現卡頓,沒法點擊的狀況或者對頁面沒法進行拖拽。
  2. 對於服務器端應用:異步編程實現了可擴展性。服務器應用能夠利用線程池知足其可擴展性,使用異步編程後,可擴展性一般能夠提升一個數量級。即提升服務器端應用的TPS(Transactions Per Second)和 QPS (Queries Per Second)

並行的兩種形式

並行編程的使用場景:須要執行大量的計算任務,而且這些任務能分割成相互獨立的任務塊兒編程

並行的形式有兩種:數據並行(data parallelism)和任務並行(task parallelim)。promise

數據並行(data parallelism):有大量的數據須要處理,而且每一塊數據的處理過程基本上是彼此獨立的。服務器

任務並行(task parallelim):須要執行大量任務,而且每一個任務的執行過程基本上是彼此獨立的。任務並行能夠是動態的,若是一個任務的執行結果會產生額外的任務,這些新增的任務也能夠加入任務池。多線程

實現數據並行的方法併發

  • Parallel.ForEach
  • PLINQ(Parallel LINQ)

每一個任務塊要儘量的互相獨立。 只要任務塊是互相獨立的,並行性就能作到最大化。一旦你在多個線程中共享狀態,就必須以同步方式訪問這些狀態,那樣程序的並行性就變差了。異步

數據並行重點在處理數據,任務並行則關注執行任務。async

實現任務並行的方法函數式編程

  • Parallel.Invoke
  • Task.Wait

一般狀況下,不必關心線程池處理任務的具體作法。數據並行和任務並行都使用動態調整的分割器,把任務分割後分配給工做線程。線程池在須要的時候會增長線程數量。線程池線程使用工做竊取隊列(work-stealing queue)。異步編程

響應式編程Rx學習難度較大

使用場景:處理的事件中帶有參數,最好採用響應式編程
響應式編程的核心概念是:可觀察的流(observable stream)
響應式編程的最終代碼很是像 LINQ,能夠認爲它就是「LINQ to events」,它採用「推送」模式,事件到達後就自行穿過查詢。函數

TPL數據流

異步編程和並行編程這兩種技術結合起來就是TPL數據流
數據流網格的基本組成單元是數據流塊(dataflow block)。

Rx 和 TPL有不少相同點。
網格和流都有「數據項」這一律念,數據項從網格或流的中間穿過。還有,網格和流都有「正常完成」(表示沒有更多數據須要接收時發出的通知)和「不正常完成」(在處理數據中發生錯誤時發出的通知)這兩個概念。可是,Rx 和 TPL 數據流的性能並不相同。

當須要執行須要計時的任務,最佳選擇是Rx的 可觀察流 observable 對象
當須要進行並行處理,最佳選擇是 TPL數據流塊

線程和線程池

線程是一個獨立的運行單元,每一個進程內部有多個線程,每一個線程能夠各自同時執行指令。每一個線程有本身獨立的棧,可是與進程內的其餘線程共享內存。
對某些程序來講,其中有一個線程是特殊的,例如用戶界面程序有一個 UI 線程,控制檯程序有一個 main 線程。

每一個 .NET 程序都有一個線程池,線程池維護着必定數量的工做線程,這些線程等待着執行分配下來的任務。線程池能夠隨時監測線程的數量。配置線程池的參數多達幾十個,可是建議採用默認設置,線程池的默認設置是通過仔細調整的,適用於絕大多數現實中的應用場景。

併發編程的設計原理

大多數併發編程技術有一個相似點:它們本質上都是函數式(functional)的。函數式編程理念是併發編程的本質。

相關文章
相關標籤/搜索