并發(fā)與并行、同步與異步、阻塞與非阻塞

下面的解釋是我個(gè)人的理解,除并發(fā)和并行,其實(shí)對(duì)于阻塞、非阻塞,同步、異步等,沒(méi)有統(tǒng)一的定義,而且有時(shí)候是可以混用的,其實(shí)大可不必過(guò)于糾結(jié)其概念。

并行/并發(fā)(Parallelism/Concurrency)

并發(fā)與并行,是用來(lái)描述任務(wù)或者說(shuō)線程的執(zhí)行方式。都表示任務(wù)同時(shí)被處理,或者說(shuō)線程在同時(shí)執(zhí)行,區(qū)別于一個(gè)一個(gè)的執(zhí)行任務(wù)。但是兩者存在細(xì)小的差別:并發(fā)特指,在一段時(shí)間內(nèi),所有的任務(wù)都達(dá)到了推進(jìn),或者說(shuō)每個(gè)任務(wù)都執(zhí)行了一部分,但是在某一個(gè)時(shí)刻,他們并非都在執(zhí)行,這通常是通過(guò)時(shí)間片的輪轉(zhuǎn)實(shí)現(xiàn)的。而并行是在真正的同時(shí)執(zhí)行,所有的任務(wù)在任何時(shí)刻都是正在執(zhí)行的。

簡(jiǎn)單描述就是:并發(fā)是N個(gè)任務(wù)通過(guò)時(shí)間片輪轉(zhuǎn)在一個(gè)CPU上執(zhí)行,并行是N個(gè)任務(wù)在N個(gè)CPU上執(zhí)行。

同步/異步(Synchronous/Asynchronous)

異步與同步是對(duì)方法調(diào)用的描述。同步調(diào)用是指,一個(gè)調(diào)用在返回結(jié)果或者因?yàn)楫惓=K止之前,調(diào)用者都無(wú)法執(zhí)行其他代碼。異步調(diào)用是指,調(diào)用會(huì)立即返回,返回值將通過(guò)回調(diào)函數(shù)等其他機(jī)制反饋給調(diào)用者。

實(shí)現(xiàn)異步調(diào)用的方式,我了解過(guò)的包括有:

Pistache的Promise機(jī)制,實(shí)現(xiàn)的方法是多線程;

Tomcat的NIO模式,實(shí)現(xiàn)的方法是epoll,即IO多路復(fù)用;

Nodejs的libuv,回調(diào)函數(shù)機(jī)制,對(duì)于文件IO采用多線程、網(wǎng)絡(luò)IO使用epoll;

Akka的Actor,使用的是郵箱-消息的信息傳遞模型,內(nèi)部也是多線程實(shí)現(xiàn)。

詳細(xì)的說(shuō),比如一個(gè)API,是訪問(wèn)數(shù)據(jù)庫(kù)的資源,那么這個(gè)過(guò)程要使用網(wǎng)絡(luò)IO,同步API,就要等待等待整個(gè)過(guò)程發(fā)生,比如連接數(shù)據(jù)庫(kù)、網(wǎng)絡(luò)數(shù)據(jù)傳輸?shù)龋划惒紸PI的實(shí)現(xiàn),可以是這樣的:

多線程模式:API的執(zhí)行會(huì)啟動(dòng)一個(gè)新的線程來(lái)負(fù)責(zé)整個(gè)事情,當(dāng)事情完成后將會(huì)通過(guò)一定的方法通知調(diào)用線程,比如回調(diào)函數(shù)、比如Actor的消息。

Epoll輪轉(zhuǎn),整個(gè)線程都是在處理Epoll的事件循環(huán),當(dāng)需要訪問(wèn)網(wǎng)絡(luò)時(shí),會(huì)在epoll上掛一個(gè)client-fd,也就是網(wǎng)絡(luò)套接字,當(dāng)接收到消息之后,epoll會(huì)產(chǎn)生特定的事件,而線程則不斷地循環(huán)處理epoll發(fā)出的各種事件!

非阻塞/阻塞(Non-blocking/Blocking)

阻塞是OS中本身存在的一個(gè)概念,比如線程在訪問(wèn)某個(gè)資源時(shí),發(fā)現(xiàn)資源不可用,這個(gè)時(shí)候我們將會(huì)阻塞線程的執(zhí)行,令其交出時(shí)間片!

阻塞是最容易和同步異步混淆的,有的人可能認(rèn)為,同步就是阻塞,異步就是非阻塞。這是為什么呢?因?yàn)橥紸PI,很多時(shí)候都是存在阻塞操作的,比如上面例子中的訪問(wèn)網(wǎng)絡(luò)I/O。

其實(shí)從概念上說(shuō),我們調(diào)用的函數(shù),都是同步調(diào)用,哪怕我們調(diào)用一個(gè)printf,根據(jù)我們的定義,是不是也是一個(gè)同步的API,但其實(shí),我們?cè)谟懻撏疆惒降臅r(shí)候,都是討論一個(gè)復(fù)雜的API,比如上面提到的訪問(wèn)網(wǎng)絡(luò)這種耗時(shí)可能長(zhǎng)達(dá)幾秒的操作,然而這些操作大都是訪問(wèn)IO等會(huì)產(chǎn)生阻塞的操作,因此會(huì)將同步與阻塞混淆!

所以說(shuō)可以這樣理解,同步和異步是對(duì)API的一個(gè)描述,而阻塞與非阻塞是對(duì)調(diào)用者的描述,如果調(diào)用者在等待結(jié)果的過(guò)程中被掛起,那么就是阻塞調(diào)用,否則就是非阻塞調(diào)用。

因此對(duì)于異步API,是不可能出現(xiàn)阻塞調(diào)用者的情況的,而對(duì)于同步的API,如果API是純CPU任務(wù),那么也是非阻塞的,而如果存在訪問(wèn)IO等操作那就是阻塞的!

其他理解

我曾經(jīng)看過(guò)一個(gè)解釋,他用了一個(gè)非常形象的例子來(lái)描述:

老王燒開(kāi)水:
1、普通水壺煮水,站在旁邊,主動(dòng)的看水開(kāi)了沒(méi)有?同步的阻塞
2、普通水壺煮水,去干點(diǎn)別的事,每過(guò)一段時(shí)間去看看水開(kāi)了沒(méi)有,水沒(méi)開(kāi)就走人。 同步非阻塞
3、響水壺煮水,站在旁邊,不會(huì)每過(guò)一段時(shí)間主動(dòng)看水開(kāi)了沒(méi)有。如果水開(kāi)了,水壺自動(dòng)通知他。 異步阻塞
4、響水壺煮水,去干點(diǎn)別的事,如果水開(kāi)了,水壺自動(dòng)通知他。異步非阻塞

雖然看上去很形象,但是我認(rèn)為是存在問(wèn)題的:

首先,等待水開(kāi)的過(guò)程,不一定就是阻塞過(guò)程,原因我之前講了,我對(duì)阻塞的理解是導(dǎo)致進(jìn)程掛起!

其次,等待響水壺,其實(shí)是將異步API同步化,這個(gè)在很多機(jī)制是常見(jiàn)的,比如先用Future機(jī)制,說(shuō)白了就是輪詢Future的值,這個(gè)過(guò)程也不能稱之為阻塞!

參考文獻(xiàn)

阻塞和非阻塞_百度百科

Terminology, Conceptsdoc.akka.io/docs/akka/current/general/terminology.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容