併發不是並行

現在我們都說設計可並行的程序、高併發的程序?而且很多時候潛意識裏面覺得對並行(Parallelism)和併發(Concurrency)的的區別很清楚,但是如果要明確的說出二者的區別,又感覺沒法給出一個非常清晰的描述。最近看到Go語言發明者之一Rob Pike的一篇演講《Concurrency is not Parallelism》,覺得挺不錯的。因爲特別喜歡的裏面的配圖示例,所以我決定寫本篇博客,將其轉過來,也方便一些網絡不暢的人。下面給出原文涉及的一些鏈接:

演講幻燈片請移步:https://talks.golang.org/2012/waza.slide
演講視頻請移步:https://www.youtube.com/watch?v=cN_DpYBzKso&t=550s

那什麼是併發?什麼又是並行呢?並行的概念比較簡單,並行總是和執行(executions)相關,很多東西同時執行就是並行;而併發則是通過一些方式組織你的程序,讓它可以分成多個模塊去獨立的執行。並行必然是需要多核的,一個處理器是無法並行的;但併發和處理器並沒有什麼必然聯繫,在一個處理器上面,我們的程序也可以是併發的。好吧,有點繞。我們直接上Rob Pike的例子:這個例子是gopher們需要將一堆過時的語言指導書用小推車推到垃圾焚燒爐去燒燬(這個例子也是非常搞笑...)。

剛開始,我們只有一個gopher,完成任務必然需要比較長的時間:

此時,如果再增加一個gopher,那也沒用,因爲它沒有車...

好吧,那我們再找輛車:

這樣雖然比之前快了,但還是有瓶頸的。因爲書只有一堆,火爐也只有一個,所以我們還必須通過消息來協調兩個gopher的行動。好吧,那我們再把書分成兩堆,再增加一個火爐:

這樣就OK了,我們就可以比之前快差不多一倍了。

這個模型就是併發的,因爲兩個gopher可以獨立的完成一件事了;但是卻不一定是並行的,比如可能同一時刻只有一個gopher是幹活的。但是我們這樣去組織的話,讓程序並行執行也會非常的容易。當然,除了這種,我們還可以設計出來很多併發模型,繼續接着看漫畫...

這次我們找了3個gopher,一個專門負責裝車,一個專門負責運輸,一個專門負責卸貨焚燒,當然三個gopher之間需要使用一些諸如消息通信之類的手段進行協調。

然而我們卻發現運輸的這個gopher很累,有瓶頸。好,我們再招聘一個gopher,專門負責還空車:

兩個gopher去搞運輸,這樣如果協調的好的話,理論情況下工作效率將是一個gopher的4倍。

這個新的併發模型就會比之前的模型更高級一點了,此時我們再將這種併發模型並行化:

漫畫還沒完,我們接着看另外一種併發模型:

運輸的gopher抱怨說運輸路程太遠,那我們就增加一箇中轉站(我覺得實際中這個gopher很可能會被解僱):

然後再將這種併發模型並行化:

我們也可以這樣設計併發模型:

然後再並行化:

OK,至此漫畫就完了。可以看到有很多種併發模型,每種模型也可以很容易的並行化起來。回到程序中,書就代表着數據;gopher就是CPU;而車可能就是一些序列化、反序列化、網絡等設施;火爐就是代理、瀏覽器或者其他的消費者。而上面的併發模型就是一個可擴展的Web Service。

至此,我們對於併發和並行的關係應該比較清楚了。最後再引用一些描述:

Concurrency is about dealing with lots of things at once.
Parallelism is about doing lots of things at once.
Not the same, but related.
Concurrency is about structure, parallelism is about execution.
Concurrency provides a way to structure a solution to solve a problem that may (but not necessarily) be parallelizable.

Parallelism is simply running things in parallel.
Concurrency is a way to structure your program.

如果喜歡看圖的,這裏再推薦一篇2016年Gopher大會上的一個演講的文章:Visualizing Concurrency in Go,裏面的配圖也非常的炫酷哦~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章