當我們討論非同步 IO模型的時候,討論的對象到底是什麼?

討論「非同步、同步」 IO等模型時候,我們討論的對象到底是什麼?

對於這個我有點疑惑,以下是我個人的一些觀點,希望大家可以指點一下:

如果整個程序是由函數構建的,那麼整個程序對於一個開發者來說分為兩個部分:調用函數(自己實現的)和被調用函數(操作系統、庫、團隊內的其他人實現的,自己不關心細節的)

1. 純粹的來說:以 Linux 下的 C 語言為例,對於一個調用函數而言,在他的實現細節內使用的被調用函數是直接的系統 API。那麼,如果這個API 的返回值可以提供返回 IO 數據,那麼他就是同步的。如果他的 IO 數據是以參數或者全局變數的形式自動錄入進用戶空間並通過信號或其他機制觸發了回調的,則是非同步的。非同步沒有阻塞與非阻塞的概念,因為非同步 API 是必定會返回的,只有同步有阻塞的概念,阻塞的表象是導致函數無法及時返回,深層含義是進程被掛起。

2.廣義的來說:如果作為一個調用者A,被調用者是「1」中的情況,那麼如「1」所述。如果被調用者B不是純粹的 API,而是由 API(C) 封裝而來的,那麼這個時候討論『同步、非同步』這些概念的對象就變成了『B』,如果 IO 數據是直接從 B 返回的,那麼就是同步,如果是通過回調(在 B 內部可能就是直接顯視的調用函數指針,但這對於 A 是不知情的)來傳達 IO 數據,則是非同步。這種情況下是存在非同步阻塞和非同步非阻塞的,如果 B 的實現是通過『忙輪詢調用同步非阻塞 API』則是『非同步阻塞的』,如果是通過『定時器加同步非阻塞 API』則是非同步非阻塞的。

在這個理解下就意味著,對於不同的調用者和被調用者語境,可以有不同的 IO 模型的解釋。

不知道我的這個理解是否正確?應該廣義的理解,還是狹義的。

還有就是,十分多的網路庫甚至除 C 外的語言(如 Python、Lua)的原生語法,他們說自己是同步或是非同步的時候是指的是對於『調用庫(或語言)的開發者而言』還是對於『調用庫(或語言)的開發者而言 使用 CAPI 的庫(或語言)而言』


IO


既然說io,同步指io完成之後返回,期間阻塞/忙等。非同步指立刻返回,之後輪詢結果或者等系統發送完成消息。

很多人陷於同步非同步字面意義,下面來說說為什麼。

假設一個請求io時間是10ms,io處理cpu參與時間為0,io外計算需要1ms。如果單線程,每秒處理請求1000/11次。那如何提高呢,以前的做法是開線程,開上幾百幾千個線程同時處理,那麼每秒可以處理請求1000/10次,io等待的時間可以用來計算了,而計算的時候,io設備也不會空著。以上是個重io的例子,性能提升並不明顯。如果計算時間也是10ms,那麼可以提高一倍。如果io時間是100ms,計算時間也是100ms,性能提升還是一樣,但是另外一個指標提高了,叫響應時間。如果系統服務有的請求需要處理時間很長,有的很短,如果沒有多線程,會因為長請求嚴重影響響應時間。就像銀行窗口排隊,前面一個人很長時間,後面排隊的都要遭殃。排隊機就是解決這個問題。排隊機不能提高效率,但是可以縮小響應時間。

Apache線程池模式就是上面說的多線程解決方案。

以前Apache絕對統治web伺服器,後來nginx崛起,佔據統治地位。nginx能夠戰勝apache的一個很重要因素是非同步模型。

非同步io不能提高性能,非同步模型才會。不要去考慮某個調用改成非同步能提高多少性能。

那麼來說說線程池的問題。現在的cpu線程切換消耗大概1微秒(估算,沒有實際測試),以前的cpu就更長。按1微秒算,每秒切換線程也就100萬次。而一個請求有很多io組成,如資料庫,redis,memcache,假設10次io,那麼得切出去切回來10次,什麼事情不幹,關線程切換,每秒也就10萬次請求。而nginx普通的電腦就能幾萬次。

線程池的目的是啥呢,說白了其實就是保存各個請求的當前狀態。那如果應用程序自己來做這個事情,是不是就可以提高性能呢。nginx就做了這事情,為了完成這件事,就得使用非同步io。整套系統叫非同步模型。不基於系統或者模型,關注於某個調用是同步還是非同步來提高性能是不切實際的。

當然nginx還有其他方面的提升,就是常常聽說的io多路復用。一個io完成之後,內核通知一次,太慢了,多路復用可以一次性通知多個io事件。

除了線程很慢,還有一個傳統的東西很慢,那就是內核陷入。而io,協議棧大都在內核空間,經常用戶態,內核態之間切換,非常耗時,為了提高系統吞吐量,人們又開始了新的努力。

解決這個問題有幾種方式,一是把應用放內核層運行,osv操作系統就在做這個事情,有些簡單的服務,比如memcache,完全可以osv跑memcache。

二是把協議棧,驅動放用戶態。用戶態協議棧已經有了。

三是減少切換次數。用戶態切換到核心態,很多情況是io中斷引起的。把頻繁觸發中斷的設備關閉中斷,如網卡,就可以了。如就用一個cpu專門處理網卡,不用中斷,直接輪詢忙等,低效的忙等這裡卻是為了提高性能。因此討論某個性能一定要看場景。dpdk就是在做2,3方面的工作。

後面部分有些跑題,權當在歷史發展過程中來看待非同步io問題。


大哥您邀錯人了吧?這說的都是啥啥啥?我看不懂啊~~~~


推薦閱讀:

如何評價Linux deepin 2014 RC版?
Linux 粉是怎樣煉成的?
如何使php5.4 , php 5.6, php7 環境 在一台伺服器上共存?
伺服器配置2 解決Your installation CD-couldn』t be mounted
Linux性能優化11:磁碟IO的調度模型

TAG:Linux | C | 網路編程 |