併發編程(8)併發算法代碼設計

本章主要內容算法

  • 線程間劃分數據的技術
  • 影響併發代碼性能的因素
  • 性能因素是如何影響數據結構的設計
  • 多線程代碼中的異常安全
  • 可擴展性
  • 並行算法的實現

  前面主要介紹了併發的數據結構,如今從高層(但也是基本的)考慮,如何使用線程,哪些代碼應該在哪些線程上執行;以及,這將如何影響代碼的清晰度,並從底層細節上了解,如何構建共享數據來優化性能。緩存

1、線程間劃分工做的技術安全

     使用線程,可使用全能的線程,用調度器調度;或者使用「專業」線程只專一完成一件事,每一個線程都有分工,或者兩者混合。數據結構

    一、在線程處理前對數據進行劃分。多線程

  最簡單的並行算法,就是並行化的 std::for_each :單位數據分配一個線程,各個線程單獨工做不會溝通,在主線程合併。併發

   二、遞歸劃分async

       (並行算法博客裏面有)快速排序模型性能

   三、任務類型劃分優化

      分離關注:QT程序將圖像處理交給圖像處理線程,防止界面卡住;主控線程等待用戶操做和線程返回。spa

      劃分任務序列:當任務會應用到相同操做序列,去處理獨立的數據項時,就可使用流水線(pipeline)系統進行併發。使用這種方式劃分工做,能夠爲流水線中的每一階段操做建立一個獨立線程。當一個操做完成,數據元素會放在隊列中,以供下一階段的線程提取使用。

     這種流水線看起來不能保證每一個線程時刻都有工做,在開頭結尾會有等待。可是一旦流動起來,對瓶頸的數據段加大優化,實現快速移動。舉例:爲了讓視頻可以播放,你至少要保證25幀每秒的解碼速度。一樣的,這些圖像須要有均勻的間隔,纔會給觀衆留有連續播放的感受;一個應用能夠在1秒解碼100幀,不過在解完就須要暫停1s的時候,這個應用就沒有意義了。另外一方面,觀衆能接受在視頻開始播放的時候有必定的延遲。這種狀況,並行使用流水線就能獲得穩定的解碼率。

2、影響併發的因素

  一、處理器數量

  一個單核16芯的處理器和四核雙芯或十六核單芯的處理器相同:在任何系統上,都能運行16個併發線程。當線程數量少於16個時,會有處理器處於空閒狀態(除非系統同時須要運行其餘應用,不過咱們暫時忽略這種可能性)。另外一方面,當多於16個線程在運行的時候(都沒有阻塞或等待),應用將會浪費處理器的運算時間在線程間進行切換,這種狀況發生時,咱們稱其爲超額認購。

  std::thread::hardware_concurrency() 能夠獲取處理器數目,可是他不會考慮正在運行的其餘線程,很容易超額認購。std::async() 就能避免這個問題,由於標準庫會對全部的調用進行適當的安排。一樣,謹慎的使用線程池也能夠避免這個問題。

    二、數據爭用與乒乓緩存

   三、超額認購致使的頻繁任務切換

   四、僞共享

     處理器緩存一般不會用來處理在單個存儲位置,但其會用來處理稱爲緩存行(cache lines)的內存塊。好比:一般int類型的大小要小於一個緩存行,同一個緩存行中能夠存儲多個數據項。每當線程訪問0號數據項,並對其值進行更新時,緩存行的全部權就須要轉移給執行該線程的處理器。而此時雖然緩存行是共享的(即便沒有數據存在),可是其餘處理器沒有控制權,沒法訪問到數據。所以使用僞共享來稱呼這種方式。

3、提升多線程性能的數據結構

  嘗試調整數據在線程間的分佈,就能讓同一線程中的數據緊密聯繫在一塊兒。

       嘗試減小線程上所需的數據量。

       嘗試讓不一樣線程訪問不一樣的存儲位置,以免僞共享。

相關文章
相關標籤/搜索