來點并發(fā)

如何提高吞吐量

快期末考試了,作為學(xué)霸的你(對,就是你!)忙的春光滿面。
一大波學(xué)妹來讓你輔導(dǎo)。
你把她們聚集到了大教室里,對她們說:一個一個來。很快一個妹子過來了,但卻得等她翻書,找題,整理思路,甚至還要先照照鏡子問你她漂亮嗎,最后才慢吞吞的開始問你題。你眼看著后面排著長隊的妹子在等著你,但你卻只能如此緩慢的一個一個親(禽)手(獸)輔導(dǎo),效率真低。一天才能接觸幾個?

這就是 單進(jìn)程單線程阻塞模式 。 如果遇到哪個妹子纏著你一天,你就別想接觸其他妹子了。

改進(jìn)一號

于是你想這么不行啊,妹子們需要你。于是你學(xué)會了分身術(shù),把自己分成N個,同時給N個妹子服務(wù),于是把妹效率提高了N倍。當(dāng)你還在高興的時候,問題出來了。

  • 教室就這么大,不可能把自己分身出太多,否則一個教室全是自己的分身,妹子進(jìn)不來,搞毛啊。 不行,一定要限制分身的數(shù)量。此時你內(nèi)心極度惆悵,唉,難道把妹效率有個不可逾越的鴻溝嗎?

  • 尼瑪,人可以分身,但水杯只有一個啊。你的分身老是輪流站著你的水杯,你早已饑渴難耐,卻拿不到水杯。于是你規(guī)定,誰拿了水杯,就在黑板上標(biāo)記一下。用完了,要及時把標(biāo)記擦掉。這樣其他分身如果看到黑板有標(biāo)記,那就等等,當(dāng)發(fā)現(xiàn)黑板沒有標(biāo)記的時候,你們就去搶,誰先搶到,他就去做標(biāo)記,獨享水杯。

但后來一些各種蛋疼原因,黑板上的標(biāo)記沒有被清除,于是你和你的分身們渴的實在沒法輔導(dǎo),于是把妹效率降低很多。

這就是 多進(jìn)程/線程模式。 目前Linux很多經(jīng)典的服務(wù)都是這種模型。

但缺點也顯而易見:

  • 多進(jìn)程/線程的數(shù)量在 一臺機(jī)器 上數(shù)量是嚴(yán)重收限制的。

    早期一些服務(wù)是動態(tài)創(chuàng)建/銷毀進(jìn)程。在當(dāng)時看起來很不錯。鏈接多了,就多來點進(jìn)程給那些大爺們服務(wù)。于是在大量鏈接的沖擊下,服務(wù)不停的創(chuàng)建新進(jìn)程,最終導(dǎo)致系統(tǒng)資源枯竭,服務(wù)器失去響應(yīng)。(現(xiàn)在的Linux會直接殺死占用內(nèi)存過多的程序,從而保證系統(tǒng)自身處于可響應(yīng)狀態(tài))

    線程雖然輕量一點,但在Linux系統(tǒng)中,線程會占用8M??臻g,對于要保持長鏈接的請求,也不可能弄多少線程出來。

  • 來,讓我們和鎖一起愉快的玩耍
    
     不說了,你們先玩,我走了
    

關(guān)于多線程還有 leader-follow, Half-Sync/Half-Async 等模式。它們對多線程做了很多優(yōu)化,可以處理大量鏈接。但我并不了解,所以這里也不做陳述。

改進(jìn)二號

恩,你想著要改進(jìn),于是先不分身了。
你有了新辦法: 你首先請了你的死黨,他就站在教室里。
然后你對妹子們說,誰準(zhǔn)備好了要我來輔導(dǎo),就先給我說一下,然后就準(zhǔn)備著,等準(zhǔn)備好了去給我兄弟說。我知道了就會叫你。

有妹子來到你這兒報名,然后她們就下去準(zhǔn)備問題了。你就把她們的名字記在一張紙上,當(dāng)你空閑的時候,你就把紙給你兄弟說,看看這上面誰準(zhǔn)備好了,然后你兄弟告訴你誰好了,你就把那個妹子叫過來,搞定后,再次把名單給你兄弟,不停的這個循環(huán)。

但后來又發(fā)現(xiàn)問題了。

  • 紙?zhí)?,來報名的妹子太多,記錄不下?/p>

  • 你在空閑的時候得把整張紙給你兄弟,你兄弟要依次看一邊名字,然后找出誰準(zhǔn)備好了。最后,還要把紙給你傳回去。

    你兄弟要抱怨了,尼瑪老子不停的看這密密麻麻的名字,好累啊。跟你傳紙的頻率比老子lu的頻率都高??!

這是 基于事件的select 模式。(或者叫多路IO復(fù)用)
它的限制很多:

  • 你需要把要監(jiān)聽的fd加入一個列表中,Linux系統(tǒng)默認(rèn)列表大小只有1024

  • 每次你都需要把這個fd列表傳遞給select調(diào)用。select調(diào)用再返回給你哪個fd上你感興趣的事件觸發(fā)了。也就是每次都需要從用戶態(tài)->內(nèi)核態(tài)->用戶態(tài)這樣拷貝一次。系統(tǒng)消耗太大
    

改進(jìn)三號

恩,select方式要不停的輪尋,限制多多,效率也沒高哪去。
于是你又改進(jìn)了一下方式:

妹子還是到你這兒來報道,但你不用紙記錄她的名字,而是立即告訴你兄弟,誰誰誰報名了,你留意下,她要是準(zhǔn)備好了,你把她名字告訴我。

然后當(dāng)你沒事干的時候,就可以睡睡覺什么的。只要等著你兄弟來叫你就行了。

這就是 epoll/kqueue/ICOP 事件回調(diào) 機(jī)制.
epoll 對應(yīng)Linux
kqueue對應(yīng)BSD
ICOP對應(yīng)Windows

不用 select 那樣的去輪尋,而是注冊fd和回調(diào),等待事件通知即可。

libevent, libev 這些庫就是將系統(tǒng)提供的事件回調(diào)機(jī)制的封裝,供上層應(yīng)用程序方便使用。


協(xié)程

當(dāng)然,除了上面那些,還有一種模型,被稱為協(xié)程。

特點如下:

  • 由程序自己產(chǎn)生,管理,調(diào)度,銷毀。和OS沒一點關(guān)系
  • 在一個OS進(jìn)程中,可以產(chǎn)生百萬級別的協(xié)程。
  • 基于協(xié)程的Actor模型不共享數(shù)據(jù),寫并發(fā)程序得心應(yīng)手

目前支持協(xié)程的語言有

這里也得提一下 Scala,它也有Actor模型,而且akka庫也很強(qiáng)大。但應(yīng)該不屬于協(xié)程范圍。

Python 是通過 Gevent 庫來實現(xiàn)的協(xié)程。

我在工作和自己的折騰中都用過Erlang和Gevent,從協(xié)程角度講,它們都很好用。

  • Erlang 在各個process之間發(fā)送消息,不共享。沒有鎖的煩惱
  • Gevent可以讓你用同步的方式來寫異步程序

看起來協(xié)程好處多多,那么 它有什么缺點呢?

  • 因為協(xié)程還是運(yùn)行在一個OS進(jìn)程中,所以協(xié)程不能跑阻塞任務(wù),否則就要將整個OS進(jìn)程阻塞住了。

后面再寫個文章具體講講我對Erlang和Gevent的看法

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

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

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