轉(zhuǎn)載:閑話高并發(fā)的那些神話外邓,看京東架構(gòu)師如何把它拉下神壇

轉(zhuǎn)載:閑話高并發(fā)的那些神話撤蚊,看京東架構(gòu)師如何把它拉下神壇

高并發(fā)也算是這幾年的熱門詞匯了,尤其在互聯(lián)網(wǎng)圈损话,開口不聊個高并發(fā)問題侦啸,都不好意思出門。高并發(fā)有那么邪乎嗎丧枪?動不動就千萬并發(fā)光涂、億級流量,聽上去的確挺嚇人拧烦。但仔細(xì)想想忘闻,這么大的并發(fā)與流量不都是通過路由器來的嗎?

>>>>

0x00 一切源自網(wǎng)卡

高并發(fā)的流量通過低調(diào)的路由器進入我們系統(tǒng)恋博,第一道關(guān)卡就是網(wǎng)卡齐佳,網(wǎng)卡怎么抗住高并發(fā)?這個問題壓根就不存在债沮,千萬并發(fā)在網(wǎng)卡看來炼吴,一樣一樣的,都是電信號疫衩,網(wǎng)卡眼里根本區(qū)分不出來你是千萬并發(fā)還是一股洪流缺厉,所以衡量網(wǎng)卡牛不牛都說帶寬,從來沒有并發(fā)量的說法隧土。

網(wǎng)卡位于物理層和鏈路層提针,最終把數(shù)據(jù)傳遞給網(wǎng)絡(luò)層(IP層),在網(wǎng)絡(luò)層有了IP地址曹傀,已經(jīng)可以識別出你是千萬并發(fā)了辐脖,所以搞網(wǎng)絡(luò)層的可以自豪的說,我解決了高并發(fā)問題皆愉,可以出來吹吹牛了嗜价。誰沒事搞網(wǎng)絡(luò)層呢?主角就是路由器幕庐,這玩意主要就是玩兒網(wǎng)絡(luò)層久锥。

>>>>

0x01 一頭霧水

非專業(yè)的我們,一般都把網(wǎng)絡(luò)層(IP層)和傳輸層(TCP層)放到一起异剥,操作系統(tǒng)提供瑟由,對我們是透明的,很低調(diào)冤寿、很靠譜歹苦,以至于我們都把他忽略了青伤。

吹過的牛是從應(yīng)用層開始的,應(yīng)用層一切都源于Socket殴瘦,那些千萬并發(fā)最終會經(jīng)過傳輸層變成千萬個Socket狠角,那些吹過的牛,不過就是如何快速處理這些Socket蚪腋。處理IP層數(shù)據(jù)和處理Socket究竟有啥不同呢丰歌?

>>>>

0x02 沒有連接,就沒用等待

最重要的一個不同就是IP層不是面向連接的屉凯,而Socket是面向連接的立帖,IP層沒有連接的概念,在IP層神得,來一個數(shù)據(jù)包就處理一個厘惦,不用瞻前也不用顧后偷仿;而處理Socket哩簿,必須瞻前顧后,Socket是面向連接的酝静,有上下文的节榜,讀到一句我愛你,激動半天别智,你不前前后后地看看宗苍,就是瞎激動了。

你想前前后后地看明白薄榛,就要占用更多的內(nèi)存去記憶讳窟,就要占用更長的時間去等待;不同連接要搞好隔離敞恋,就要分配不同的線程(或者協(xié)程)丽啡。所有這些都解決好,貌似還是有點難度的硬猫。

>>>>

0x03 感謝操作系統(tǒng)

操作系統(tǒng)是個好東西补箍,在Linux系統(tǒng)上,所有的IO都被抽象成了文件啸蜜,網(wǎng)絡(luò)IO也不例外坑雅,被抽象成Socket,但是Socket還不僅是一個IO的抽象衬横,它同時還抽象了如何處理Socket裹粤,最著名的就是select和epoll了,知名的nginx蜂林、netty蛹尝、redis都是基于epoll搞的后豫,這仨家伙基本上是在千萬并發(fā)領(lǐng)域必備神技。

但是多年前突那,Linux只提供了select的挫酿,這種模式能處理的并發(fā)量非常小,而epoll是專為高并發(fā)而生的愕难,感謝操作系統(tǒng)早龟。不過操作系統(tǒng)沒有解決高并發(fā)的所有問題,只是讓數(shù)據(jù)快速地從網(wǎng)卡流入我們的應(yīng)用程序猫缭,如何處理才是老大難葱弟。

操作系統(tǒng)的使命之一就是最大限度的發(fā)揮硬件的能力,解決高并發(fā)問題猜丹,這也是最直接芝加、最有效的方案,其次才是分布式計算射窒。前面我們提到的nginx藏杖、netty、redis都是最大限度發(fā)揮硬件能力的典范脉顿。如何才能最大限度的發(fā)揮硬件能力呢蝌麸?

>>>>0x04 核心矛盾

要最大限度的發(fā)揮硬件能力,首先要找到核心矛盾所在艾疟。我認(rèn)為来吩,這個核心矛盾從計算機誕生之初直到現(xiàn)在,幾乎沒有發(fā)生變化蔽莱,就是CPU和IO之間的矛盾弟疆。

CPU以摩爾定律的速度野蠻發(fā)展,而IO設(shè)備(磁盤盗冷,網(wǎng)卡)卻乏善可陳怠苔。龜速的IO設(shè)備成為性能瓶頸,必然導(dǎo)致CPU的利用率很低正塌,所以提升CPU利用率幾乎成了發(fā)揮硬件能力的代名詞嘀略。

>>>>

0x05 中斷與緩存

CPU與IO設(shè)備的協(xié)作基本都是以中斷的方式進行的,例如讀磁盤的操作乓诽,CPU僅僅是發(fā)一條讀磁盤到內(nèi)存的指令給磁盤驅(qū)動帜羊,之后就立即返回了,此時CPU可以接著干其他事情鸠天,讀磁盤到內(nèi)存本身是個很耗時的工作讼育,等磁盤驅(qū)動執(zhí)行完指令,會發(fā)個中斷請求給CPU,告訴CPU任務(wù)已經(jīng)完成奶段,CPU處理中斷請求饥瓷,此時CPU可以直接操作讀到內(nèi)存的數(shù)據(jù)。

中斷機制讓CPU以最小的代價處理IO問題痹籍,那如何提高設(shè)備的利用率呢呢铆?答案就是緩存。

操作系統(tǒng)內(nèi)部維護了IO設(shè)備數(shù)據(jù)的緩存蹲缠,包括讀緩存和寫緩存棺克,讀緩存很容易理解,我們經(jīng)常在應(yīng)用層使用緩存线定,目的就是盡量避免產(chǎn)生讀IO娜谊。

寫緩存應(yīng)用層使用的不多,操作系統(tǒng)的寫緩存斤讥,完全是為了提高IO寫的效率纱皆。操作系統(tǒng)在寫IO的時候會對緩存進行合并和調(diào)度,例如寫磁盤會用到電梯調(diào)度算法芭商。

>>>>

0x06 高效利用網(wǎng)卡

高并發(fā)問題首先要解決的是如何高效利用網(wǎng)卡派草。網(wǎng)卡和磁盤一樣,內(nèi)部也是有緩存的蓉坎,網(wǎng)卡接收網(wǎng)絡(luò)數(shù)據(jù)澳眷,先存放到網(wǎng)卡緩存胡嘿,然后寫入操作系統(tǒng)的內(nèi)核空間(內(nèi)存)蛉艾,我們的應(yīng)用程序則讀取內(nèi)存中的數(shù)據(jù),然后處理衷敌。

除了網(wǎng)卡有緩存外勿侯,TCP/IP協(xié)議內(nèi)部還有發(fā)送緩沖區(qū)和接收緩沖區(qū)以及SYN積壓隊列、accept積壓隊列缴罗。

這些緩存助琐,如果配置不合適,則會出現(xiàn)各種問題面氓。例如在TCP建立連接階段兵钮,如果并發(fā)量過大,而nginx里面socket的backlog設(shè)置的值太小舌界,就會導(dǎo)致大量連接請求失敗掘譬。

如果網(wǎng)卡的緩存太小,當(dāng)緩存滿了后呻拌,網(wǎng)卡會直接把新接收的數(shù)據(jù)丟掉戒洼,造成丟包狂秦。當(dāng)然如果我們的應(yīng)用讀取網(wǎng)絡(luò)IO數(shù)據(jù)的效率不高鲸湃,會加速網(wǎng)卡緩存數(shù)據(jù)的堆積蕾殴。如何高效讀取網(wǎng)絡(luò)數(shù)據(jù)呢?目前在Linux上廣泛應(yīng)用的就是epoll了绎速。

操作系統(tǒng)把IO設(shè)備抽象為文件,網(wǎng)絡(luò)被抽象成了Socket,Socket本身也是一個文件本谜,所以可以用read/write方法來讀取和發(fā)送網(wǎng)絡(luò)數(shù)據(jù)。在高并發(fā)場景下偎窘,如何高效利用Socket快速讀取和發(fā)送網(wǎng)絡(luò)數(shù)據(jù)呢耕突?

要想高效利用IO,就必須在操作系統(tǒng)層面了解IO模型评架,在《UNIX網(wǎng)絡(luò)編程》這本經(jīng)典著作里眷茁,總結(jié)了五種IO模型,分別是阻塞式IO纵诞,非阻塞式IO上祈,多路復(fù)用IO,信號驅(qū)動IO和異步IO浙芙。

>>>>

0x07 阻塞式IO

我們以讀操作為例登刺,當(dāng)我們調(diào)用read方法讀取Socket上的數(shù)據(jù)時,如果此時Socket讀緩存是空的(沒有數(shù)據(jù)從Socket的另一端發(fā)過來)嗡呼,操作系統(tǒng)會把調(diào)用read方法的線程掛起纸俭,直到Socket讀緩存里有數(shù)據(jù)時,操作系統(tǒng)再把該線程喚醒南窗。

當(dāng)然揍很,在喚醒的同時,read方法也返回了數(shù)據(jù)万伤。我理解所謂的阻塞窒悔,就是操作系統(tǒng)是否會掛起線程。

>>>>

0x08 非阻塞式IO

而對于非阻塞式IO敌买,如果Socket的讀緩存是空的简珠,操作系統(tǒng)并不會把調(diào)用read方法的線程掛起,而是立即返回一個EAGAIN的錯誤碼虹钮,在這種情景下聋庵,可以輪詢read方法,直到Socket的讀緩存有數(shù)據(jù)則可以讀到數(shù)據(jù)芙粱,這種方式的缺點非常明顯祭玉,就是消耗大量的CPU。

>>>>

0x09 多路復(fù)用IO

對于阻塞式IO宅倒,由于操作系統(tǒng)會掛起調(diào)用線程攘宙,所以如果想同時處理多個Socket屯耸,就必須相應(yīng)地創(chuàng)建多個線程,線程會消耗內(nèi)存蹭劈,增加操作系統(tǒng)進行線程切換的負(fù)載疗绣,所以這種模式不適合高并發(fā)場景。有沒有辦法較少線程數(shù)呢铺韧?

非阻塞IO貌似可以解決多矮,在一個線程里輪詢多個Socket,看上去可以解決線程數(shù)的問題哈打,但實際上這個方案是無效的塔逃,原因是調(diào)用read方法是一個系統(tǒng)調(diào)用,系統(tǒng)調(diào)用是通過軟中斷實現(xiàn)的料仗,會導(dǎo)致進行用戶態(tài)和內(nèi)核態(tài)的切換湾盗,所以很慢。

但是這個思路是對的立轧,有沒有辦法避免系統(tǒng)調(diào)用呢格粪?有,就是多路復(fù)用IO氛改。

在Linux系統(tǒng)上select/epoll這倆系統(tǒng)API支持多路復(fù)用IO帐萎,通過這兩個API,一個系統(tǒng)調(diào)用可以監(jiān)控多個Socket胜卤,只要有一個Socket的讀緩存有數(shù)據(jù)了疆导,方法就立即返回,然后你就可以去讀這個可讀的Socket了葛躏,如果所有的Socket讀緩存都是空的澈段,則會阻塞,也就是將調(diào)用select/epoll的線程掛起紫新。

所以select/epoll本質(zhì)上也是阻塞式IO均蜜,只不過他們可以同時監(jiān)控多個Socket李剖。

>>>>

0x0A select和epoll的區(qū)別

為什么多路復(fù)用IO模型有兩個系統(tǒng)API芒率?我分析原因是,select是POSIX標(biāo)準(zhǔn)中定義的篙顺,但是性能不夠好偶芍,所以各個操作系統(tǒng)都推出了性能更好的API,如Linux上的epoll德玫、Windows上的IOCP匪蟀。

至于select為什么會慢,大家比較認(rèn)可的原因有兩點宰僧,一點是select方法返回后材彪,需要遍歷所有監(jiān)控的Socket,而不是發(fā)生變化的Ssocket,還有一點是每次調(diào)用select方法段化,都需要在用戶態(tài)和內(nèi)核態(tài)拷貝文件描述符的位圖(通過調(diào)用三次copy_from_user方法拷貝讀嘁捷、寫、異常三個位圖)显熏。epoll可以避免上面提到的這兩點雄嚣。

>>>>

0x0B Reactor多線程模型

在Linux操作系統(tǒng)上,性能最為可靠喘蟆、穩(wěn)定的IO模式就是多路復(fù)用缓升,我們的應(yīng)用如何能夠利用好多路復(fù)用IO呢?經(jīng)過前人多年實踐總結(jié)蕴轨,搞了一個Reactor模式港谊,目前應(yīng)用非常廣泛,著名的Netty橙弱、Tomcat NIO就是基于這個模式封锉。

Reactor的核心是事件分發(fā)器和事件處理器,事件分發(fā)器是連接多路復(fù)用IO和網(wǎng)絡(luò)數(shù)據(jù)處理的中樞膘螟,核心就是監(jiān)聽Socket事件(select/epoll_wait)成福,然后將事件分發(fā)給事件處理器,事件分發(fā)器和事件處理器都可以基于線程池來做荆残。

需要重點提一下的是奴艾,在Socket事件中主要有兩大類事件,一個是連接請求内斯,另一個是讀寫請求蕴潦,連接請求成功處理之后會創(chuàng)建新的Socket,讀寫請求都是基于這個新創(chuàng)建的Socket俘闯。

所以在網(wǎng)絡(luò)處理場景中潭苞,實現(xiàn)Reactor模式會稍微有點繞,但是原理沒有變化真朗。具體實現(xiàn)可以參考Doug Lea的《Scalable IO in Java》(http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf)

Reactor原理圖

>>>>

0x0C Nginx多進程模型

Nginx默認(rèn)采用的是多進程模型此疹,Nginx分為Master進程和Worker進程,真正負(fù)責(zé)監(jiān)聽網(wǎng)絡(luò)請求并處理請求的只有Worker進程遮婶,所有的Worker進程都監(jiān)聽默認(rèn)的80端口蝗碎,但是每個請求只會被一個Worker進程處理。

這里面的玄機是:每個進程在accept請求前必須爭搶一把鎖旗扑,得到鎖的進程才有權(quán)處理當(dāng)前的網(wǎng)絡(luò)請求蹦骑。每個Worker進程只有一個主線程,單線程的好處是無鎖處理臀防,無鎖處理并發(fā)請求眠菇,這基本上是高并發(fā)場景里面的最高境界了边败。(參考http://www.dre.vanderbilt.edu/~schmidt/PDF/reactor-siemens.pdf)

數(shù)據(jù)經(jīng)過網(wǎng)卡、操作系統(tǒng)捎废、網(wǎng)絡(luò)協(xié)議中間件(Tomcat放闺、Netty等)重重關(guān)卡,終于到了我們應(yīng)用開發(fā)人員手里缕坎,我們?nèi)绾翁幚磉@些高并發(fā)的請求呢怖侦?我們還是先從提升單機處理能力的角度來思考這個問題。

>>>>0x0D 突破木桶理論

據(jù)經(jīng)過網(wǎng)卡谜叹、操作系統(tǒng)匾寝、中間件(Tomcat、Netty等)重重關(guān)卡荷腊,終于到了我們應(yīng)用開發(fā)人員手里艳悔,我們?nèi)绾翁幚磉@些高并發(fā)的請求呢?

我們還是先從提升單機處理能力的角度來思考這個問題女仰,在實際應(yīng)用的場景中猜年,問題的焦點是如何提高CPU的利用率(誰叫它發(fā)展的最快呢),木桶理論講最短的那根板決定水位疾忍,那為啥不是提高短板IO的利用率乔外,而是去提高CPU的利用率呢?

這個問題的答案是在實際應(yīng)用中一罩,提高了CPU的利用率往往會同時提高IO的利用率杨幼。當(dāng)然在IO利用率已經(jīng)接近極限的條件下,再提高CPU利用率是沒有意義的聂渊。我們先來看看如何提高CPU的利用率差购,后面再看如何提高IO的利用率。

>>>>0x0E 并行與并發(fā)

提升CPU利用率目前主要的方法是利用CPU的多核進行并行計算汉嗽,并行和并發(fā)是有區(qū)別的欲逃,在單核CPU上,我們可以一邊聽MP3饼暑,一邊Coding稳析,這個是并發(fā),但不是并行撵孤,因為在單核CPU的視野迈着,聽MP3和Coding是不可能同時進行的。

只有在多核時代邪码,才會有并行計算。并行計算這東西太高級咬清,工業(yè)化應(yīng)用的模型主要有兩種闭专,一種是共享內(nèi)存模型奴潘,另外一種是消息傳遞模型。

>>>>

0x0F 多線程設(shè)計模式

對于共享內(nèi)存模型影钉,其原理基本都來自大師Dijkstra在半個世紀(jì)前(1965)的一篇論文《Cooperating sequential processes》画髓,這篇論文提出了大名鼎鼎的概念信號量,Java里面用于線程同步的wait/notify也是信號量的一種實現(xiàn)平委。

大師的東西看不懂奈虾,學(xué)不會也不用覺得丟人,畢竟大師的嫡傳子弟也沒幾個廉赔。東洋有個叫結(jié)城浩的總結(jié)了一下多線程編程的經(jīng)驗肉微,寫了本書叫《JAVA多線程設(shè)計模式》,這個還是挺接地氣(能看懂)的蜡塌。下面簡單介紹一下碉纳。

1. Single Threaded Execution

這個模式是把多線程變成單線程,多線程在同時訪問一個變量時馏艾,會發(fā)生各種莫名其妙的問題劳曹,這個設(shè)計模式直接把多線程搞成了單線程,于是安全了琅摩,當(dāng)然性能也就下來了铁孵。最簡單的實現(xiàn)就是利用synchronized將存在安全隱患的代碼塊(方法)保護起來。在并發(fā)領(lǐng)域有個臨界區(qū)(criticalsections)的概念房资,我感覺和這個模式是一回事库菲。

2. Immutable Pattern

如果共享變量永遠(yuǎn)不變,那就多個線程訪問就沒有任何問題志膀,永遠(yuǎn)安全熙宇。這個模式雖然簡單,但是用的好溉浙,能解決很多問題烫止。

3. Guarded Suspension Patten

這個模式其實就是等待-通知模型,當(dāng)線程執(zhí)行條件不滿足時戳稽,掛起當(dāng)前線程(等待)馆蠕,當(dāng)條件滿足時,喚醒所有等待的線程(通知)惊奇,在Java語言里利用synchronized互躬,wait/notifyAll可以很快實現(xiàn)一個等待通知模型。結(jié)城浩將這個模式總結(jié)為多線程版的If颂郎,我覺得非常貼切吼渡。

4. Balking

這個模式和上個模式類似,不同點是當(dāng)線程執(zhí)行條件不滿足時直接退出乓序,而不是像上個模式那樣掛起寺酪。這個用法最大的應(yīng)用場景是多線程版的單例模式坎背,當(dāng)對象已經(jīng)創(chuàng)建了(不滿足創(chuàng)建對象的條件)就不用再創(chuàng)建對象(退出)。

5. Producer-Consumer

生產(chǎn)者-消費者模式寄雀,全世界人都知道得滤。我接觸的最多的是一個線程處理IO(如查詢數(shù)據(jù)庫),一個(或者多個)線程處理IO數(shù)據(jù)盒犹,這樣IO和CPU就都能成分利用起來懂更。如果生產(chǎn)者和消費者都是CPU密集型,再搞生產(chǎn)者-消費者就是自己給自己找麻煩了急膀。

6. Read-Write Lock

讀寫鎖解決的讀多寫少場景下的性能問題沮协,支持并行讀,但是寫操作只允許一個線程做脖阵。如果寫操作非常非常少皂股,而讀的并發(fā)量非常非常大,這個時候可以考慮使用寫時復(fù)制(copy on write)技術(shù)命黔,我個人覺得應(yīng)該單獨把寫時復(fù)制單獨作為一個模式呜呐。

7. Thread-Per-Message

就是我們經(jīng)常提到的一請求一線程。

8. Worker Thread

一請求一線程的升級版悍募,利用線程池解決線程的頻繁創(chuàng)建蘑辑、銷毀導(dǎo)致的性能問題。BIO年代Tomcat就是用的這種模式坠宴。

9. Future

當(dāng)你調(diào)用某個耗時的同步方法很心煩洋魂,想同時干點別的事情,可以考慮用這個模式喜鼓,這個模式的本質(zhì)是個同步變異步的轉(zhuǎn)換器副砍。同步之所以能變異步,本質(zhì)上是啟動了另外一個線程庄岖,所以這個模式和一請求一線程還是多少有點關(guān)系的豁翎。

10. Two-Phase Termination

這個模式能解決優(yōu)雅地終止線程的需求。

11. Thread-Specific Storage

線程本地存儲隅忿,避免加鎖心剥、解鎖開銷的利器,C#里面有個支持并發(fā)的容器ConcurrentBag就是采用了這個模式背桐,這個星球上最快的數(shù)據(jù)庫連接池HikariCP借鑒了ConcurrentBag的實現(xiàn)优烧,搞了個Java版的,有興趣的同學(xué)可以參考链峭。

12. Active Object(這個不講也罷)

這個模式相當(dāng)于降龍十八掌的最后一掌畦娄,綜合了前面的設(shè)計模式,有點復(fù)雜,個人覺得借鑒的意義大于參考實現(xiàn)纷责。

最近國人也出過幾本相關(guān)的書捍掺,但總體還是結(jié)城浩這本更能經(jīng)得住推敲撼短≡偕牛基于共享內(nèi)存模型解決并發(fā)問題,主要問題就是用好鎖曲横,但是用好鎖喂柒,還是有難度的,所以后來又有人搞了消息傳遞模型禾嫉,這個后面再聊灾杰。

基于共享內(nèi)存模型解決并發(fā)問題,主要問題就是用好鎖熙参,但是用好鎖艳吠,還是有難度的,所以后來又有人搞了消息傳遞模型孽椰。

>>>>

0x10 消息傳遞模型

共享內(nèi)存模型難度還是挺大的昭娩,而且你沒有辦法從理論上證明寫的程序是正確的,我們總一不小心就會寫出來個死鎖的程序來黍匾,每當(dāng)有了問題栏渺,總會有大師出來,于是消息傳遞(Message-Passing)模型橫空出世(發(fā)生在上個世紀(jì)70年代)锐涯,消息傳遞模型有兩個重要的分支磕诊,一個是Actor模型,一個是CSP模型纹腌。

>>>>

0x11 Actor模型

Actor模型因為Erlang聲名鵲起霎终,后來又出現(xiàn)了Akka。在Actor模型里面升薯,沒有操作系統(tǒng)里所謂進程莱褒、線程的概念,一切都是Actor覆劈,我們可以把Actor想象成一個更全能保礼、更好用的線程。

在Actor內(nèi)部是線性處理(單線程)的责语,Actor之間以消息方式交互炮障,也就是不允許Actor之間共享數(shù)據(jù),沒有共享坤候,就無需用鎖胁赢,這就避免了鎖帶來的各種副作用。

Actor的創(chuàng)建和new一個對象沒有啥區(qū)別白筹,很快智末、很小谅摄,不像線程的創(chuàng)建又慢又耗資源;Actor的調(diào)度也不像線程會導(dǎo)致操作系統(tǒng)上下文切換(主要是各種寄存器的保存系馆、恢復(fù))送漠,所以調(diào)度的消耗也很小。

Actor還有一個有點爭議的優(yōu)點由蘑,Actor模型更接近現(xiàn)實世界闽寡,現(xiàn)實世界也是分布式的、異步的尼酿、基于消息的爷狈、尤其Actor對于異常(失敗)的處理裳擎、自愈涎永、監(jiān)控等都更符合現(xiàn)實世界的邏輯。

但是這個優(yōu)點改變了編程的思維習(xí)慣鹿响,我們目前大部分編程思維習(xí)慣其實是和現(xiàn)實世界有很多差異的(這個回頭再細(xì)說)羡微,一般來講,改變我們思維習(xí)慣的事情抢野,阻力總是超乎我們的想象拷淘。

>>>>

0x12 CSP模型

Golang在語言層面支持CSP模型,CSP模型和Actor模型的一個感官上的區(qū)別是在CSP模型里面指孤,生產(chǎn)者(消息發(fā)送方)和消費者(消息接收方)是完全松耦合的启涯,生產(chǎn)者完全不知道消費者的存在,但是在Actor模型里面恃轩,生產(chǎn)者必須知道消費者结洼,否則沒辦法發(fā)送消息。

CSP模型類似于我們在多線程里面提到的生產(chǎn)者-消費者模型叉跛,核心的區(qū)別我覺得在于CSP模型里面有類似綠色線程(green thread)的東西松忍,綠色線程在Golang里面叫做協(xié)程,協(xié)程同樣是個非常輕量級的調(diào)度單元筷厘,可以快速創(chuàng)建而且資源占用很低鸣峭。

Actor在某種程度上需要改變我們的思維方式,而CSP模型貌似沒有那么大動靜酥艳,更容易被現(xiàn)在的開發(fā)人員接受摊溶,都說Golang是工程化的語言,在Actor和CSP的選擇上充石,也可以看到這種體現(xiàn)莫换。

>>>>

0x13 多樣世界

除了消息傳遞模型,還有事件驅(qū)動模型、函數(shù)式模型拉岁。事件驅(qū)動模型類似于觀察者模式坷剧,在Actor模型里面,消息的生產(chǎn)者必須知道消費者才能發(fā)送消息喊暖,而在事件驅(qū)動模型里面惫企,事件的消費者必須知道消息的生產(chǎn)者才能注冊事件處理邏輯。

Akka里消費者可以跨網(wǎng)絡(luò)哄啄,事件驅(qū)動模型的具體實現(xiàn)如Vertx里雅任,消費者也可以訂閱跨網(wǎng)絡(luò)的事件风范,從這個角度看咨跌,大家都在取長補短。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末硼婿,一起剝皮案震驚了整個濱河市锌半,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌寇漫,老刑警劉巖刊殉,帶你破解...
    沈念sama閱讀 211,496評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異州胳,居然都是意外死亡记焊,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,187評論 3 385
  • 文/潘曉璐 我一進店門栓撞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來遍膜,“玉大人,你說我怎么就攤上這事瓤湘∑奥” “怎么了?”我有些...
    開封第一講書人閱讀 157,091評論 0 348
  • 文/不壞的土叔 我叫張陵弛说,是天一觀的道長挽懦。 經(jīng)常有香客問我,道長木人,這世上最難降的妖魔是什么信柿? 我笑而不...
    開封第一講書人閱讀 56,458評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮醒第,結(jié)果婚禮上渔嚷,老公的妹妹穿的比我還像新娘。我一直安慰自己淘讥,他們只是感情好圃伶,可當(dāng)我...
    茶點故事閱讀 65,542評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般窒朋。 火紅的嫁衣襯著肌膚如雪搀罢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,802評論 1 290
  • 那天侥猩,我揣著相機與錄音榔至,去河邊找鬼。 笑死欺劳,一個胖子當(dāng)著我的面吹牛唧取,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播划提,決...
    沈念sama閱讀 38,945評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼枫弟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了鹏往?” 一聲冷哼從身側(cè)響起淡诗,我...
    開封第一講書人閱讀 37,709評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎伊履,沒想到半個月后韩容,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,158評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡唐瀑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,502評論 2 327
  • 正文 我和宋清朗相戀三年群凶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哄辣。...
    茶點故事閱讀 38,637評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡请梢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出柔滔,到底是詐尸還是另有隱情血崭,我是刑警寧澤漏峰,帶...
    沈念sama閱讀 34,300評論 4 329
  • 正文 年R本政府宣布债热,位于F島的核電站旭咽,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏超全。R本人自食惡果不足惜咆霜,卻給世界環(huán)境...
    茶點故事閱讀 39,911評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嘶朱。 院中可真熱鬧蛾坯,春花似錦、人聲如沸疏遏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,744評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至倘零,卻和暖如春唱遭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背呈驶。 一陣腳步聲響...
    開封第一講書人閱讀 31,982評論 1 266
  • 我被黑心中介騙來泰國打工拷泽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人袖瞻。 一個月前我還...
    沈念sama閱讀 46,344評論 2 360
  • 正文 我出身青樓司致,卻偏偏與公主長得像,于是被迫代替她去往敵國和親聋迎。 傳聞我的和親對象是個殘疾皇子脂矫,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,500評論 2 348

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