事件驅(qū)動(dòng)模型、Nodejs作為事件驅(qū)動(dòng)模型與多線(xiàn)程編程模型之間的對(duì)比

聲明:本文的內(nèi)容多是取自網(wǎng)上的一些概念、材料,梳理了一下看過(guò)之后自己的理解(文章中會(huì)注明部分內(nèi)容來(lái)源)

本文的學(xué)習(xí)目的:nodejs是一門(mén)事件驅(qū)動(dòng)模型的技術(shù),但是以前看到的時(shí)候,老是一概而過(guò),今天細(xì)想之下,發(fā)現(xiàn)自己只是模糊的知其然,而不知所以然,所以今天就想系統(tǒng)的梳理一下:nodejs作為事件驅(qū)動(dòng)模型的技術(shù)與傳統(tǒng)ThreadPerConnection多線(xiàn)程模型的區(qū)別?

首先,什么是事件驅(qū)動(dòng)模型?

通俗點(diǎn)來(lái)講:事件驅(qū)動(dòng)模型與消息驅(qū)動(dòng)模型的區(qū)別

假設(shè)系統(tǒng)是這樣的:處理A事后還有B事要處理
    事件驅(qū)動(dòng)程序模型:(類(lèi)似發(fā)布訂閱模式)
        告訴處理A事的程序B事是如何做的,在A事處理完后,直接調(diào)用處理B事的程序(或接口)來(lái)處理B事。

    消息驅(qū)動(dòng)程序模型:
        處理完A事,放個(gè)消息在某個(gè)地方,意思是我處理完A事了,此時(shí),處理A的程序已經(jīng)完事大吉了。至于何時(shí),如何處理B事,由另一個(gè)程序根據(jù)那個(gè)消息來(lái)處理。這就是基于消息的。
        在需要等待條件觸發(fā)時(shí),B會(huì)不斷地檢查這個(gè)條件,直到條件滿(mǎn)足,這是很浪費(fèi)cpu時(shí)間的

兩種驅(qū)動(dòng)模型的運(yùn)用:

Windows消息

當(dāng)一個(gè)窗體或者控件需要讓另外一個(gè)窗體或者消息執(zhí)行某個(gè)動(dòng)作,就向那個(gè)窗體發(fā)一個(gè)消息,放到對(duì)方的消息隊(duì)列中,然后對(duì)方有一個(gè)消息循環(huán)不停的讀取消息隊(duì)列,并執(zhí)行相應(yīng)的動(dòng)作。

C#事件

某個(gè)窗體或者控件在執(zhí)行某個(gè)動(dòng)作的時(shí)候(或者之前、或者之后)會(huì)主動(dòng)引發(fā)一個(gè)事件,如果其他窗體或者控件對(duì)這個(gè)事件感興趣,就可以注冊(cè)這個(gè)事件,從而在事件被引發(fā)時(shí)可以執(zhí)行一些相關(guān)的操作。

iOS的事件就得提到runloop循環(huán)機(jī)制:

一個(gè)死循環(huán),這個(gè)死循環(huán)包括兩個(gè)部分,第一個(gè)部分是按照一定的條件接收并選擇一個(gè)要處理的事件(IOKit傳來(lái)的事件),第二個(gè)部分就是事件的處理過(guò)程(hitTest消息處理)。
程序的執(zhí)行過(guò)程就是選擇事件和處理事件,而當(dāng)沒(méi)有任何事件觸發(fā)時(shí),程序會(huì)因查詢(xún)事件隊(duì)列失敗而進(jìn)入睡眠狀態(tài),從而釋放cpu。

事件驅(qū)動(dòng)模型 詳解

來(lái)自百科

1.要理解事件驅(qū)動(dòng)和程序,就需要與非事件驅(qū)動(dòng)的程序進(jìn)行比較。實(shí)際上,現(xiàn)代的程序大多是事件驅(qū)動(dòng)的,比如多線(xiàn)程的程序,肯定是事件驅(qū)動(dòng)的。早期則存在許多非事件驅(qū)動(dòng)的程序,這樣的程序,在需要等待某個(gè)條件觸發(fā)時(shí),會(huì)不斷地檢查這個(gè)條件,直到條件滿(mǎn)足,這是很浪費(fèi)cpu時(shí)間的。而事件驅(qū)動(dòng)的程序,則有機(jī)會(huì)釋放cpu從而進(jìn)入睡眠態(tài)(注意是有機(jī)會(huì),當(dāng)然程序也可自行決定不釋放cpu),當(dāng)事件觸發(fā)時(shí)被操作系統(tǒng)喚醒,這樣就能更加有效地使用cpu.

2.再說(shuō)什么是事件驅(qū)動(dòng)的程序。一個(gè)典型的事件驅(qū)動(dòng)的程序,就是一個(gè)死循環(huán),并以一個(gè)線(xiàn)程的形式存在,這個(gè)死循環(huán)包括兩個(gè)部分,第一個(gè)部分是按照一定的條件接收并選擇一個(gè)要處理的事件,第二個(gè)部分就是事件的處理過(guò)程。程序的執(zhí)行過(guò)程就是選擇事件和處理事件,而當(dāng)沒(méi)有任何事件觸發(fā)時(shí),程序會(huì)因查詢(xún)事件隊(duì)列失敗而進(jìn)入睡眠狀態(tài),從而釋放cpu。

3.事件驅(qū)動(dòng)的程序,必定會(huì)直接或者間接擁有一個(gè)事件隊(duì)列,用于存儲(chǔ)未能及時(shí)處理的事件。

4.事件驅(qū)動(dòng)的程序的行為,完全受外部輸入的事件控制,所以,事件驅(qū)動(dòng)的系統(tǒng)中,存在大量這種程序,并以事件作為主要的通信方式。

5.事件驅(qū)動(dòng)的程序,還有一個(gè)最大的好處,就是可以按照一定的順序處理隊(duì)列中的事件,而這個(gè)順序則是由事件的觸發(fā)順序決定的,這一特性往往被用于保證某些過(guò)程的原子化。

6.目前windows,linux,nucleus,vxworks都是事件驅(qū)動(dòng)的,只有一些單片機(jī)可能是非事件驅(qū)動(dòng)的。

事件模式耦合高,同模塊內(nèi)好用;消息模式耦合低,跨模塊好用。事件模式集成其它語(yǔ)言比較繁瑣,消息模式集成其他語(yǔ)言比較輕松。事件是侵入式設(shè)計(jì),霸占你的主循環(huán);消息是非侵入式設(shè)計(jì),將主循環(huán)該怎樣設(shè)計(jì)的自由留給用戶(hù)。如果你在設(shè)計(jì)一個(gè)東西舉棋不定,那么你可以參考win32的GetMessage,本身就是一個(gè)藕合度極低的接口,又足夠自由,接口任何語(yǔ)言都很方便,具體應(yīng)用場(chǎng)景再在其基礎(chǔ)上封裝成事件并不是難事,接口耦合較低,即便哪天事件框架調(diào)整,修改外層即可,不會(huì)傷經(jīng)動(dòng)骨。而如果直接實(shí)現(xiàn)成事件,那就完全反過(guò)來(lái)了。

單線(xiàn)程編程模型、多線(xiàn)程編程模型、事件驅(qū)動(dòng)模型(單線(xiàn)程模型)的對(duì)比?

以下內(nèi)容來(lái)自https://blog.csdn.net/solo_ws/article/details/50731868

事件驅(qū)動(dòng)編程是一種編程范式,這里程序的執(zhí)行流由外部事件來(lái)決定。它的特點(diǎn)是包含一個(gè)事件循環(huán),當(dāng)外部事件發(fā)生時(shí)使用回調(diào)機(jī)制來(lái)觸發(fā)相應(yīng)的處理。另外兩種常見(jiàn)的編程范式是(單線(xiàn)程)同步以及多線(xiàn)程編程。

讓我們用例子來(lái)比較和對(duì)比一下單線(xiàn)程、多線(xiàn)程以及事件驅(qū)動(dòng)編程模型。下圖中展示了隨著時(shí)間的推移,這三種模式下程序所做的工作。這個(gè)程序有3個(gè)任務(wù)需要完成,每個(gè)任務(wù)都在等待I/O操作時(shí)阻塞自身。阻塞在I/O操作上所花費(fèi)的時(shí)間已經(jīng)用灰色框標(biāo)示出來(lái)了。


三種類(lèi)型編程模型的對(duì)比.png
單線(xiàn)程同步模型

任務(wù)按照順序執(zhí)行。如果某個(gè)任務(wù)因?yàn)镮/O而阻塞,其他所有的任務(wù)都必須等待,直到它完成之后它們才能依次執(zhí)行。這種明確的執(zhí)行順序和串行化處理的行為是很容易推斷得出的。如果任務(wù)之間并沒(méi)有互相依賴(lài)的關(guān)系,但仍然需要互相等待的話(huà)這就使得程序不必要的降低了運(yùn)行速度。

多線(xiàn)程版本

這3個(gè)任務(wù)分別在獨(dú)立的線(xiàn)程中執(zhí)行。這些線(xiàn)程由操作系統(tǒng)來(lái)管理,在多處理器系統(tǒng)上可以并行處理,或者在單處理器系統(tǒng)上交錯(cuò)執(zhí)行。這使得當(dāng)某個(gè)線(xiàn)程阻塞在某個(gè)資源的同時(shí)其他線(xiàn)程得以繼續(xù)執(zhí)行。與完成類(lèi)似功能的同步程序相比,這種方式更有效率,但程序員必須寫(xiě)代碼來(lái)保護(hù)共享資源,防止其被多個(gè)線(xiàn)程同時(shí)訪(fǎng)問(wèn)。多線(xiàn)程程序更加難以推斷,因?yàn)檫@類(lèi)程序不得不通過(guò)線(xiàn)程同步機(jī)制如鎖、可重入函數(shù)、線(xiàn)程局部存儲(chǔ)或者其他機(jī)制來(lái)處理線(xiàn)程安全問(wèn)題,如果實(shí)現(xiàn)不當(dāng)就會(huì)導(dǎo)致出現(xiàn)微妙且令人痛不欲生的bug。

事件驅(qū)動(dòng)模型

在事件驅(qū)動(dòng)版本的程序中,3個(gè)任務(wù)交錯(cuò)執(zhí)行,但仍然在一個(gè)單獨(dú)的線(xiàn)程控制中。當(dāng)處理I/O或者其他昂貴的操作時(shí),注冊(cè)一個(gè)回調(diào)到事件循環(huán)中,然后當(dāng)I/O操作完成時(shí)繼續(xù)執(zhí)行?;卣{(diào)描述了該如何處理某個(gè)事件。事件循環(huán)輪詢(xún)所有的事件,當(dāng)事件到來(lái)時(shí)將它們分配給等待處理事件的回調(diào)函數(shù)。這種方式讓程序盡可能的得以執(zhí)行而不需要用到額外的線(xiàn)程。事件驅(qū)動(dòng)型程序比多線(xiàn)程程序更容易推斷出行為,因?yàn)槌绦騿T不需要關(guān)心線(xiàn)程安全問(wèn)題。

優(yōu)缺點(diǎn)補(bǔ)充:

以下內(nèi)容來(lái)自https://blog.csdn.net/jmxyandy/article/details/7338889

ThreadPerConnection的多線(xiàn)程模型(比如Java

優(yōu)點(diǎn):簡(jiǎn)單易用,效率也不錯(cuò)。在這種模型中,開(kāi)發(fā)者使用同步操作來(lái)編寫(xiě)程序,比如使用阻塞型I/O。使用同步操作的程序能夠隱式地在線(xiàn)程的運(yùn)行堆棧中維護(hù)應(yīng)用程序的狀態(tài)信息和執(zhí)行歷史,方便程序的開(kāi)發(fā)。

缺點(diǎn):沒(méi)有足夠的擴(kuò)展性。如果應(yīng)用程序只需處理少量的并發(fā)連接,那么對(duì)應(yīng)地創(chuàng)建相應(yīng)數(shù)量的線(xiàn)程,一般的機(jī)器都還能勝任;但如果應(yīng)用程序需要處理成千上萬(wàn)個(gè)連接,那么為每個(gè)連接創(chuàng)建一個(gè)線(xiàn)程也許是不可行的。

事件驅(qū)動(dòng)的單線(xiàn)程模型

優(yōu)點(diǎn):擴(kuò)展性高,通常性能也比較好。在這種模型中,把會(huì)導(dǎo)致阻塞的操作轉(zhuǎn)化為一個(gè)異步操作,主線(xiàn)程負(fù)責(zé)發(fā)起這個(gè)異步操作,并處理這個(gè)異步操作的結(jié)果。由于所有阻塞的操作都轉(zhuǎn)化為異步操作,理論上主線(xiàn)程的大部分時(shí)間都是在處理實(shí)際的計(jì)算任務(wù),少了多線(xiàn)程的調(diào)度時(shí)間,所以這種模型的性能通常會(huì)比較好。

缺點(diǎn):要把所有會(huì)導(dǎo)致阻塞的操作轉(zhuǎn)化為異步操作。一個(gè)是帶來(lái)編程上的復(fù)雜度,異步操作需要由開(kāi)發(fā)者來(lái)顯示地管理應(yīng)用程序的狀態(tài)信息和執(zhí)行歷史。第二個(gè)是目前很多廣泛使用的函數(shù)庫(kù)都很難轉(zhuǎn)為用異步操作來(lái)實(shí)現(xiàn),即是可以用異步操作來(lái)實(shí)現(xiàn),也將進(jìn)一步增加編程的復(fù)雜度。

并發(fā)系統(tǒng)通常既包含異步處理服務(wù),又包含同步處理服務(wù)。系統(tǒng)程序員有充分的理由使用異步特性改善性能。相反,應(yīng)用程序員也有充分的理由使用同步處理簡(jiǎn)化他們的編程強(qiáng)度。

當(dāng)我們面對(duì)如下的環(huán)境時(shí),事件驅(qū)動(dòng)模型通常是一個(gè)好的選擇:

  • 程序中有許多任務(wù),而且…
  • 任務(wù)之間高度獨(dú)立(因此它們不需要互相通信,或者等待彼此)而且…
  • 在等待事件到來(lái)時(shí),某些任務(wù)會(huì)阻塞。

當(dāng)應(yīng)用程序需要在任務(wù)間共享可變的數(shù)據(jù)時(shí),這也是一個(gè)不錯(cuò)的選擇,因?yàn)檫@里不需要采用同步處理。

網(wǎng)絡(luò)應(yīng)用程序通常都有上述這些特點(diǎn),這使得它們能夠很好的契合事件驅(qū)動(dòng)編程模型。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容