非同步io有什麼優勢?
純種的非同步io把 「從內核拷貝數據到進程」這個任務交給了內核來做,進程只會被通知數據到達。
請問這種模式有什麼優勢呢?修改上文,只討論io過程,真正的io操作都會阻塞進程。同步io時候 進程調用read函數讓內核拷貝數據過來,非同步時候內核拷貝好了通知進程,進程不會阻塞。我問過一些高手,可還是有疑問:1.有的人說是為了不佔用底層io資源:聽起來有道理,但是很多網路庫根本不是用SIGIO信號實現的,而是poll上的封裝,模擬了一個非同步io過程,這提升不了性能2.有人說是為了節省線程:這個更費解,如果數據處理過程複雜的話,該啟動還是得啟動啊,不複雜的話用多路復用足夠了
最好舉個應用場景 謝謝!
首先,你說的那種在開個用戶線程來模擬的非同步io,確實在性能上沒有任何優勢,這點毋庸置疑。至於為什麼要這麼做,往下看。
那在內核上處理的真正非同步io的優勢在於:
和同步非阻塞io相比,優勢主要在於不用維護數據讀不齊時的邏輯處理。你看各個用非阻塞io的庫,很多都有一層recv_n/send_n,或者類似邏輯的封裝。和同步阻塞io相比,最大的優勢在於在io數很多的時候,減少了線程數。還有一點,非同步io因為所有和網路相關的處理全部由內核來完成了,所以上層代碼只關注邏輯和少量與此調度相關的api,基本不再直接接觸系統io相關的內容。所以很容易寫出跨系統移植的代碼,這對一些有這要求的庫是有一定的吸引力的——這也是為什麼你看到的很多庫都要用一個線程來模擬非同步io的原因了,它不是為了性能,而是為了跨平台移植方便。在Linux下,我沒有見過誰用非同步IO。
你要叫滴滴打車,有以下幾種做法:
- 叫車之後,就一直在路口等著,車來了自己上去——同步、阻塞
- 叫車之後,一邊等著一邊看美女,車來了自己上去——同步,非阻塞
- 叫車之後,光顧著看美女,司機到了之後打電話給你——非同步、非阻塞
即是:同步就是你要自己檢查車來了沒有;非同步就是車來了司機聯繫你。阻塞就是等車的時候老實等著,別干別的(被阻塞);非阻塞就是等車的時候你可以做其他事情。
「從內核拷貝數據到進程」這個任務不在內核做,還能在用戶態做?你以為read(2)能在用戶模式下從內核空間里複製數據?非同步IO相對於非阻塞同步IO(如select/epoll),主要優點是編程模式和阻塞同步IO更接近,編程難度較低。非阻塞同步IO由於是內核通知用戶代碼可以讀/寫的位元組數,與應用邏輯可能不匹配,需要用戶代碼自己維護緩衝區/狀態機。然而如今大部分應用間通訊基於HTTP而不是TCP,一方面應用代碼在HTTP庫之上編程,不用碰select/epoll/iocp,另一方面HTTP這文本協議你用非同步IO照樣免不了緩衝區和狀態機,因此沒什麼優勢。至於各位搞不清非同步和非阻塞同步的答主嘛,我看和提問者比起來,你們還需要學習一個。
好處在於,你可以很方便的將多個非同步操作歸併為一個。如果是nonblock則不太容易做到。考慮你要實現一個非同步版本的readn,你能很容易組合多個非同步的read,只要在完成函數里發出下一個read就行。如果read是nonblock的話,你想想該如何實現一個nonblock的readn。
另一個好處是,nonblock必須有一個buffer在緩存數據。而非同步則要靈活一些。雖然linux下常用的系統api都是nonblock的,但是程序模塊之間很少見到用這種模式的,比如你要提供一個querydb的介面給其他模塊用,query可能比較耗時,你想想看這個api如果實現成非同步就只要加一個callback參數就行,而如果要搞成nonblock的怎麼搞。不要去算一個調用的性能比,要看整個系統。拿web伺服器來說,如果同步調用,那麼線程經常阻塞,為了提高吞吐量,必須開大量線程,幾萬幾十萬,這個系統開銷是非常大的,線程切換的開銷也很大,假如每秒服務10萬請求,每個請求都是一個線程,那麼至少切換10萬/核次線程。這個開銷是很大的。這也是nginx可以同時處理幾萬幾十萬,而Apache大都幾千就了不起了。現在為了高性能都避免使用線程,一般一個虛擬cpu一個線程,盡量避免線程切換,這個在後端一般都這樣設計。我以前對比過nginx加php-fpm跟nginx內嵌lua的性能對比,不在一個數量級,不是說php性能比lua差很多,而是體系決定的。lua內嵌入nginx,可以使用nginx這套非同步模式。而php-fpm做不到,如果哪天php也能內嵌入nginx,性能也會大幅提高。
吞吐量。比如銀行櫃檯前一個用戶在填表的時候會讓後一個用戶上來遞材料,而不是讓櫃員乾等。這並不改變兩個用戶業務處理的絕對時間,其實也不節省什麼資源(non-blocking io說的能節省資源,是一個side effect,因為進程不幹等就不用維護棧,省點內存),但櫃員的工作吞吐量增加了。
單個節點吞吐量高了,服務需要的節點數就可以減少,省錢。蟹妖。
同步非同步的區別汁乎上有很多了,建議你自己去搜索一下。我就簡單按照自己的理解說明一下:
- 同步指的是發起請求要等待請求應答才繼續。這個應答指的是函數返回一定的結果,並且一般不需要後續通知。比如用select去確定一個fd_set有沒有返回結果,就是同步操作。- 非同步指的是發起請求後不需要等待結果,而是通過後續回調或是通知機製得到結果。比如你用iocp註冊了一個消息回調函數,當有消息過來的時候調用你的處理函數,就是非同步操作。區別在哪呢?
如果用同步,需要不斷的通過select去查數據,就會不斷的進行用戶態和內核態切換,而且你還不確定啥時候數據才能到來,要幾秒鐘select一次比較好,比較費資源,在大並發不固定頻率io環境中很低效。如果用非同步,就可以讓os在恰當的時機通知你數據到來,不需要你去頻繁查詢了。但是這樣會佔用內核資源,而且對於很多iocp實現來說,是線程掛起的,線程太多也會造成一定的資源浪費。當然,我說的只是目前實現上的區別,實際上同步和非同步的概念在實現中並沒有很嚴格的定義。
比如你說的把 「從內核拷貝數據到進程」這個任務交給了內核來做,就不是非同步的特有概念,非同步完全可以做到只通知你數據到來,然後讓你自己調用io函數把數據從內核取到用戶進程地址空間去。1、非同步io大致形成一個通知鏈。否則就是輪詢。通知鏈比輪詢效率要高。
2、同步io、非同步io,用戶態和內核都要做工作。非同步io用戶態的工作比較少,更有優勢。題主可以去研究一下著名的非同步I/O模型IOCP,保證對你的問題秒答甚至還有更多額外收穫。
場景:一個單伺服器完全可以承載一個肩負重數據寫/重度計算需求和實時性要求很高的大型網路遊戲同時10萬用戶在線的需求。事件驅動不在上層做就在底層做,有區別嗎?
同步非阻塞需要切換查看吧,非同步有通知機制
Windows的話,樓主搜搜recv和wsarecv函數描述吧,可能有幫助
@陳碩 的答案,及下面一些評論,說的是GNU C庫實現的一套非同步IO介面,底層確實是用線程來模擬的,所以相比同步IO,並沒有什麼本質的優勢或不同。然而在2.6內核中,已經引入了原生的非同步IO了。所謂的非同步,就是用戶空間的數據需要手動對齊到4K,然後由磁碟驅動直接direct IO從內存中的用戶空間取數據,並寫入磁碟中。這是真正的非同步IO,因為過程中完全沒有寫入內核緩衝區的操作。而在磁碟驅動進行拷貝時,CPU可以去做其他的事情。
非同步io相對同步io可以提高吞吐量。因為非同步把真正的io操作交給操作系統/其他線程執行,主線程可以直接往後跑了;同步的話無論如何也要等io完成才能繼續執行。
另外,很多人拿同步io關注事件開始、非同步io關注事件完成作為同步非同步io的區別,我認為這點不是它們的本質區別,拿這個來舉例子多半是受了國內網路上各種以訛傳訛的博客的影響,並沒有理解到關鍵點。
推薦閱讀:
※2017 年 Linux 在桌面平台上有前景嗎?
※如何說服後端技術人員放棄 SQL Server 轉向 MySQL?
※怎樣才算有自主知識產權的操作系統?研發「自主知識產權」的操作系統對中國的社會和經濟有何意義?
※把 Linux 當作主要工作系統,在裡面能幹什麼,可以做哪些長知識的事情?
※WebQQ準備停止服務,是不是發布新版Linux QQ的前兆?