天天看點

并發不是并行,它更好!

現代社會是并行的:多核、網絡、雲計算、使用者負載,并發技術對此有用。

go語言支援并發,它提供了:并發執行(goroutines),同步和消息(channels)和多路并發控制(select)。

并發和并行的差別

當go聲稱是并發時,人們說:“并發很酷!耶,我可以并行運作了!”,但這是個錯誤的。因為很多人都不了解他們間的差别。“我用四個處理器來做質數篩選,但是更慢了。”

并發(concurrency):以可獨立執行的程序集合的方式程式設計(程序是出了名的難定義,這裡是通常意義上的程序,不是linux程序)

并行(parallelism):以可同時執行的(可能相關的)計算指令方式程式設計。

兩者的差別:并發是同時處理(dealing)很多的事情,并行是同時做(doing)很多的事情。不同,但也相關。一個是關于代碼結構,一個是關于代碼執行。并發為可能的(不是必須的)并行問題提供了一種解決方案。比如:

滑鼠、鍵盤、顯示器、磁盤驅動是并發結構的。

向量點積是并行的。

并發帶有通信

并發是一種構造程式的方式,把任務分解為一個個獨立運作的小任務。通信是協調這些小任務的手段。

go的模型(還有erlang等)都是基于cps(communicating sequential processes,通信順序程序):其論文c. a. r. hoare: communicating sequential processes (cacm 1978)

通過一個例子來了解

以上講得太抽象了,我們舉實際點的例子。

我們的問題:把一堆廢棄語言的說明書運到火爐裡,一隻地鼠會花費很長時間。

并發不是并行,它更好!

更多的地鼠

并發不是并行,它更好!

單單更多的地鼠也不解決問題,它們需要更多的推車。

更多的地鼠、更多的推車

并發不是并行,它更好!

這樣會加快速度,但它們會在那堆書和爐子那邊遇上瓶頸。同時也要同步兩隻地鼠,可以通過消息的方式實作。

全部加倍

并發不是并行,它更好!

這樣會以兩倍的速度運送。這是兩個地鼠程式的并發構成(concurrent composition)。

但這種設計不是自發并行的,如果一次隻有一隻地鼠在運會怎樣?

這種設計仍是并發,不是并行。[譯者注:一隻地鼠運一次上面那堆書,然後第二隻地鼠再運一次下面那堆書。一次隻允許一隻地鼠運送,這樣就不是并行的。]

然而,這種場景是可以自發并行的。并發構成可以考慮下其他模型。

另一種設計

并發不是并行,它更好!

三隻地鼠在工作,但可能會有延誤。每隻地鼠是個獨立的步驟,附加協調(通信)。

更細粒度的并發

并發不是并行,它更好!

增加一隻地鼠用來運回空推車。四隻地鼠在工作,運作得更加流暢,每隻地鼠都在做一個簡單的任務。

如果我們把事情安排的足夠好(現實中很難但不是不可能),速度會是最先隻有一隻地鼠的那個設計的四倍。

觀察結論:我們在一個已有的設計(指三個地鼠的那個設計)中添加一個并發的步驟(第四隻地鼠)增強了系統的性能。更多的地鼠幹了更多的活,系統運作得更好。并發比簡單的并行對問題要有更深的洞察。

我們有四個并發的步驟:1.裝書到推車上2.把推車運到火爐邊3.把書卸到火爐裡4.運回空推車

不同的并發設計能以不同的方式來并行。

更多的并行

并發不是并行,它更好!

我們以另一個次元來并行,并行使這樣的設計變的容易。八隻地鼠,都在繁忙工作。

但也可能根本沒有并行

謹記:即使一次隻能有一隻地鼠在工作(零并行),這也不失為一個良好的并發的解決方案。

下面也是一種用并發組成來解決問題的設計。兩隻地鼠,再加上一個中轉堆。

并發不是并行,它更好!

以一般的方式來并行

用更多的并發程式來提高吞吐量

并發不是并行,它更好!

或者一種不同的方式

在多地鼠并發模型中引入中轉堆

并發不是并行,它更好!

全面優化

使用我們所有的技術,16隻地鼠都開足馬力。

并發不是并行,它更好!

學到内容

我們有很多方法把問題分解,這才是并發設計。一旦我們分解了問題,并行就自然而然的産生了,正确性也變得很容易。

回到計算

我們關于運書的問題,可以看做是如下的類比:書堆是web資料,地鼠是cpu,推車是排程、渲染或是網絡,火堆是代理、浏覽器或是其他的消費者。地鼠提供網絡資料,這就是一個可擴充的web服務的并發設計了

繼續閱讀