每個(gè)開(kāi)發(fā)人員都應(yīng)該了解這些術(shù)語(yǔ)中更深的細(xì)微差別
當(dāng)您說(shuō)某個(gè)特定的框架是"異步","非阻塞"和"事件驅(qū)動(dòng)"時(shí),請(qǐng)確保使用正確的詞。
當(dāng)您的同事將某種東西描述為非阻塞的異步I / O時(shí),這意味著什么。 是否可以使用阻塞的異步I / O? 如果不是,非阻塞和異步意味著同一件事嗎? 在本文中,我將解釋這些(以及許多其他)常用(經(jīng)常被濫用)的軟件工程術(shù)語(yǔ)的正確含義和用法。
并發(fā)與并行執(zhí)行并發(fā)-重疊執(zhí)行或時(shí)間分片。 并發(fā)是一種編程屬性,即使對(duì)于單核計(jì)算機(jī)也可能發(fā)生。
并行性-同時(shí)執(zhí)行。 這是執(zhí)行硬件的屬性,其中任務(wù)實(shí)際上同時(shí)進(jìn)行。


同步與AsyncSynchronous-在同步操作的情況下,發(fā)起操作的一方必須等待操作完成。
異步-在異步操作中,啟動(dòng)器不需要等待操作完成。 它可以繼續(xù)進(jìn)行下一步,而無(wú)需等待對(duì)方的結(jié)果。 稍后可以通過(guò)其他某種機(jī)制來(lái)檢測(cè)操作的完成。 除了編程,該概念還可以應(yīng)用于其他領(lǐng)域。 電子郵件是異步通信的一個(gè)示例,而電話(huà)對(duì)話(huà)是同步的。


阻塞與非阻塞這是一個(gè)編程概念,與編寫(xiě)代碼的方式有關(guān)(與同步與異步不同)。 如果函數(shù)調(diào)用立即返回一個(gè)值,則稱(chēng)為非阻塞。 在某些情況下,例如I / O,功能的邏輯完成結(jié)果無(wú)法立即獲得。 但是,它將引用返回到占位符,該值稍后將可用。 例如,Java Future。 即使該值僅在10秒鐘后可用,以下函數(shù)也會(huì)立即返回。
- public Future<Integer> calculate(Integer input) {
- return executor.submit(() -> {
- Thread.sleep(10000); return input * input;
- });
- }
異步函數(shù)調(diào)用不能阻塞。
取決于上下文,非阻塞和異步可能意味著相同,也可能不同。 雖然電子郵件通信是異步的,但將電子郵件稱(chēng)為非阻塞性呼叫并沒(méi)有任何意義。
命令式與聲明式編程風(fēng)格
聲明式編程是一種編程范例,用于表達(dá)計(jì)算的邏輯(要做什么)而不描述其控制流程(如何做)。 例如SQL命令。
命令式編程是一種編程范式,它根據(jù)更改程序狀態(tài)的語(yǔ)句來(lái)描述計(jì)算。
下面的示例循環(huán)遍歷數(shù)字1到10,并找到偶數(shù)。
- List<Integer> numbersOneThroughTen = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
- //With imperative programming, we'd step through this, and decide //what we want:
- List<Integer> evenNumbers = new ArrayList<>();
- for (Integer eachValue : numbersOneThroughTen) {
- if (eachValue % 2 == 0) {
- evenNumbers.add(eachValue);
- }
- }
- //The following code uses declarative programming to accomplish the //same thing.
- // Here, we're saying "Give us everything where it's odd"
- evenNumbers = numbersOneThroughTen.stream().filter(num -> num % 2 == 0)
- .collect(Collectors.toList());
注意:這是一個(gè)抽象概念。 在上面的示例中,您可以進(jìn)一步說(shuō)我們沒(méi)有得到" foreach"的實(shí)際實(shí)現(xiàn),因此從某種意義上說(shuō),它是在描述"做什么"而不是"如何做"。 從純粹的命令式到純粹的聲明式,每種編程風(fēng)格都處在某種范圍內(nèi)。 函數(shù)式編程比過(guò)程式編程更具聲明性。
功能編程一種程序設(shè)計(jì)范例,其中通過(guò)應(yīng)用和組合功能來(lái)構(gòu)造程序。 在函數(shù)式編程中,將函數(shù)視為一等公民,這意味著它們可以綁定到名稱(chēng)(包括本地標(biāo)識(shí)符),作為參數(shù)傳遞并從其他函數(shù)返回,就像任何其他數(shù)據(jù)類(lèi)型一樣。 這允許程序以聲明性和可組合的方式編寫(xiě),其中將小的功能組合在一起以創(chuàng)建更大的功能和程序。 純函數(shù)式編程是所有函數(shù)均為純函數(shù)的函數(shù)式編程的子集。 我將寫(xiě)另一篇有關(guān)函數(shù)式編程的詳細(xì)博客文章。
事件驅(qū)動(dòng)或基于消息的體系結(jié)構(gòu)事件是系統(tǒng)狀態(tài)的重大變化。 例如,當(dāng)消費(fèi)者購(gòu)買(mǎi)汽車(chē)時(shí),汽車(chē)的狀態(tài)將從"待售"變?yōu)?quot;已售出"。 汽車(chē)經(jīng)銷(xiāo)商的系統(tǒng)體系結(jié)構(gòu)可以將此狀態(tài)更改視為一個(gè)事件,該事件的發(fā)生可以被體系結(jié)構(gòu)內(nèi)的其他應(yīng)用程序知道。 嚴(yán)格來(lái)說(shuō),事件無(wú)法傳播,只會(huì)發(fā)生。 發(fā)出,處理和傳播的實(shí)際上是事件的通知-以純文本消息的形式。 在事件驅(qū)動(dòng)的系統(tǒng)中,不同的參與組件通過(guò)異步消息進(jìn)行通信。
響應(yīng)式系統(tǒng)與響應(yīng)式編程響應(yīng)式系統(tǒng)是一種程序,其體系結(jié)構(gòu)允許它對(duì)運(yùn)行時(shí)環(huán)境中的更改做出反應(yīng)。 反應(yīng)性系統(tǒng)(http://www.reactivemanifesto.org)中正式規(guī)定了反應(yīng)性系統(tǒng)應(yīng)具有的屬性。 這些屬性中的三個(gè)可以概括為響應(yīng),彈性和彈性。
響應(yīng)式意味著響應(yīng)式系統(tǒng)可以實(shí)時(shí)響應(yīng)輸入,而不是延遲一個(gè)簡(jiǎn)單的查詢(xún),因?yàn)樵撓到y(tǒng)正在為其他人處理大量工作。
彈性意味著系統(tǒng)通常不會(huì)因?yàn)橐粋€(gè)組件發(fā)生故障而失敗; 斷開(kāi)的網(wǎng)絡(luò)鏈接不會(huì)影響不涉及該鏈接的查詢(xún),對(duì)無(wú)響應(yīng)組件的查詢(xún)可以重新路由到備用組件。
彈性意味著系統(tǒng)可以適應(yīng)其工作負(fù)載的變化并繼續(xù)有效執(zhí)行。 由于您可能會(huì)在提供食物和提供飲料之間的欄中動(dòng)態(tài)地重新分配人員,以使兩行的等待時(shí)間都相似,因此您可以調(diào)整與各種軟件服務(wù)相關(guān)的工作線(xiàn)程數(shù),以確保沒(méi)有工人閑置,同時(shí)確保每個(gè)隊(duì)列繼續(xù) 待處理。
顯然,這些屬性可以通過(guò)多種方式實(shí)現(xiàn),但是一種主要方法是使用反應(yīng)式編程風(fēng)格。
響應(yīng)式編程是使用表示為異步消息的事件進(jìn)行編程(如在事件驅(qū)動(dòng)的體系結(jié)構(gòu)中)。 這些消息通常被建模為數(shù)據(jù)流。 例如,在Web應(yīng)用程序中,典型的單擊事件可以建模為數(shù)據(jù)流,您可以在該數(shù)據(jù)流上觀(guān)察并產(chǎn)生一些副作用。 您可以創(chuàng)建任何數(shù)據(jù)流,而不僅僅是單擊和懸停事件。 流既便宜又無(wú)處不在,任何事物都可以是流:變量,用戶(hù)輸入,屬性,緩存,數(shù)據(jù)結(jié)構(gòu)等。例如,您的Twitter feed是一種與單擊事件相同的數(shù)據(jù)流。 您可以收聽(tīng)該流并做出相應(yīng)的反應(yīng)。
流可以用作另一流的輸入。 甚至多個(gè)流也可以用作另一個(gè)流的輸入。 您可以合并兩個(gè)流。 您可以過(guò)濾流以獲得另一個(gè)只包含您感興趣的事件的流。您可以將數(shù)據(jù)值從一個(gè)流映射到另一個(gè)新流。