並行和併發
基本概念
並行和併發的區別
並行(parallel)
同時做某些事情,可以互不干擾的同時做幾件事。
舉例
:高速公路的車道,雙向4車道,所有車輛(資料)可以互不干擾的在自己的車道上奔跑 (傳輸)。
在同一個時刻,每條車道上可能同時有車輛在跑,是同時發生的概念。
如下圖所示,在t時刻可以有多個程式在執行中,這樣就稱作並行。 (注意是同一時刻,不是同一個時間段)

併發,(concurrency)
也是同時做某些事,但是強調,同一個時段做幾件事
鄉村公路一條車道,半幅路面出現了坑,交警指揮車輛走另外半幅路面,一個方向放行3分鐘,
停止方向,換另一個方向放行。發生了車輛同時要通過路面的事件,這就是併發。
如下圖所示,在T時間段內可以有多個程式在執行中,這樣就稱作併發。 (注意是同一時間段,一般這個時間段都指的是一個比較小的時間段,不是同一個時刻)

經典的生產者和消費者模型
比如有這樣一個生產者:一個賣煎餅果子的老奶奶,在沒有人買的時候可多做出幾個讓後放在架子上,但是架子上的容量是有限的,比如最多能放10個,當老奶奶想空餘的時間多做出幾個放在架子上的時候每次都要看一看架子上有沒有空餘的空間來放做出來的煎餅果子。
比如有這樣的消費者:很多喜歡吃煎餅果子的小姐姐,都喜歡到老奶奶這裡來買煎餅果子,如果小姐姐來的早,在架子上有很多已經做好了的煎餅果子,然後小姐姐只要一來,看一看架子上是否有做好了的煎餅果子,如果有就直接就買上走人了,但是晚來的小哥哥就沒有那麼運氣好了,當他來的時候架子上沒有了,只有等待著老奶奶做好了再賣給他。
併發的解決
舉例“食堂打飯”:
很多人都肯定經歷過,中午12點,下課後一望無際的腦袋都湧向食堂,(一小撮吃外賣的不算,並不是很多人家裡都富有,我也是隻有吃食堂的份了)。特別是在12:00--12:30這個時間段人流量是最大的,這就叫做高併發。為了使得食堂不會因為我們人數太多了供應不過來,崩掉了。所以食堂就要求我們排隊,這就相當於我們程式的訊息隊列了,使用佇列的方式是一個可以解決併發的一種方法,雖然這種方法不一定很好,但是這是解決併發的一種方法。
所以第一種解決辦法就是: 佇列、緩衝區
:
其實在食堂的打飯視窗前都有大片用來排隊的區域,這樣一個容納學生的區域就叫做緩衝區,也就是在程式中暫時存放資料的地方。
緩衝區技術最開始提出來是用在處理記憶體和CUP的速度問題的,大家都知道記憶體讀寫很快,但是我們CUP的計算能力更是日益更加的強大,就出現了,記憶體的讀寫資料跟不上CUP的處理資料,然後人們就發明了cache(快取),CUP在處理資料的時候先把資料放入IO資料更快的cache中,然後再進行處理,也可以理解成,cache就是一個數據臨時存放的地方,一般的計算機中都有多級快取,CUP中一般也有cache,CUP中的cache一般稱作片內cahe。
優先佇列
假設今天是女神節,學校為了給學校的女神們過節日,然後就出現了這樣一個規則,只要有女生來打飯就直接去最前面,不用跟在男生後面進行排隊。這樣的一個佇列,在程式設計中就叫做優先佇列。
但是作為一個理工科大學,女生還是寥寥無幾。
這種優先佇列的方式還是不太好,還有什麼其他的方法呢?
我們可以這樣思考,比如我們去食堂打飯,然後不排隊了,直接就往裡面衝,但是我們注意的是總有人先去到窗口裡面,每個打飯的阿姨都只能給一個打飯的同學服務。也可以叫做這個同學把這樣阿姨佔用了,在我們程式設計裡面,當你去請求一個資源的時候,如果你動作夠快,然後佔用了這個資源,然後就把這個資源給鎖上了。
所以第二種解決辦法就是: 爭搶、鎖資源
:
但是這樣方法也不是很好,比如:有的同學為了搶著先打飯,甚至爭的鼻青臉腫的。也比如說某個中學佔用了一個打飯的阿姨,但是他在哪裡想了一半天都沒有想好吃什麼,後面判斷的同學就一直在後面等著,最後都爭吵起來了。還有一種情況就是比如某個同學平時也不鍛鍊,身體素質很差,更本就搶不贏其他的同學。(在Linux核心中其實也是這種爭搶機制,比如我們人類的社會,如果你太弱就搶不贏別人,最後物競天擇……,所以我們要努力學習,增強自己。)
雖然爭搶式的方式有很多的問題,但是我們也不能只看缺點,同時爭搶式也有優點,比如:比如可以激勵我們的同學節省打飯的時間。
這學期我們學校的一個食堂就升級了,以前是同學們走到打飯的視窗前面,要吃什麼然後再叫阿姨打,但是這樣效率並不是很高。所以這學期就換成了這樣的機制,阿姨們提前把飯和菜提前用小點的碗和盤子盛好,然後同學們走到視窗前面就只要看著自己喜歡的菜和飯,端著就走了,到另外的地方買單就好。
所以第三種解決辦法就是: 預處理
:
預處理的核心思想就是提前準備好使用者請求的資源。這不失為一個好的辦法。
另外比如學校因為招到了很多的新生,食堂常常是人滿為患,所以學校就準備擴建了。另外又修了一棟樓來開食堂。導致打飯的視窗也變多了,但是這樣花費就大了,如果學校沒有這樣的積蓄是蓋不起大樓的。
所以第四種解決辦法就是: 並行
:
比如我們最以前的8086晶片就只是單核心的,現在都是多核心的,處理的速度自然就提升了上來,比如打飯的視窗多了,同學們打到飯的速度也就變快了。
後面又接著分析,食堂的阿姨因為工作不積極,或者說是業務能力不行,打飯的動作太慢了,出現了這種情況怎麼辦呢,也就有解僱,然後招聘能力更好的打飯的阿姨了。
所以第五種解決辦法就是: 提速
:
這種提速就是更換新的東西,比如我們電腦執行速度越來越卡了,所以也就只用換更好的CUP,速度更快的記憶體。但是這種提升比較不常用,比如:我們現在就算你高薪請一個能力很強的阿姨但是,人重視要累的,所以這種提升是有上限的。
我們應該在坐飛機或者坐火車的時候,常常在安檢的時候地方前面有個很長的用鐵欄杆為其他的走廊,我們所有要過安檢的人先從這個走廊中依次排隊進入,當排完隊後,後面就可以進入到各個安檢口,檢查身體和行李了。
所以第六種解決辦法就是: 訊息中介軟體
:
常見的訊息中介軟體有RabbitMQ、ActiveMQ ( Apache )、RocketMQ (阿里Apache )、kafka ( Apache )等。
當然還有其他手段解決併發問題,但是已經列舉除了最常用的解決方案,一般來說不同的併發場景用不同的策略,而策略可能是多種方式的優化組合。
可能有的人無法區分上面我講的,訊息佇列和訊息中介軟體,這兩種方法的區別,其實這兩種本質上都是訊息佇列的機制,只是前一種是在我服務的內部實現,二後一種是在服務的外部實現