IO多路複用技術(multiplexing)

1、舉例說明html

  假設你是一個老師,讓30個學生解答一道題目,而後檢查學生作的是否正確,你有下面幾個選擇:react

1. 第一種選擇: 按順序逐個檢查,先檢查A,而後是B,以後是C、D。。。這中間若是有一個學生卡主,全班都會被耽誤。
這種模式就比如,你用循環挨個處理socket,根本不具備併發能力。
2. 第二種選擇:你 建立30個分身,每一個分身檢查一個學生的答案是否正確。 這種相似於爲每個用戶建立一個進程或者線程處理鏈接。
3. 第三種選擇,你 站在講臺上等,誰解答完誰舉手。這時C、D舉手,表示他們解答問題完畢,你下去依次檢查C、D的答案,而後繼續回到講臺上等。此時E、A又舉手,而後去處理E和A。。。
這種就是IO複用模型,Linux下的select、poll和epoll就是幹這個的。將用戶socket對應的fd註冊進epoll,而後epoll幫你監聽哪些socket上有消息到達,這樣就避免了大量的無用操做。此時的socket應該採用 非阻塞模式
這樣,整個過程只在調用select、poll、epoll這些調用的時候纔會阻塞,收發客戶消息是不會阻塞的,整個進程或者線程就被充分利用起來,這就是 事件驅動,所謂的reactor模式。
(做者:郭春陽
連接:https://www.zhihu.com/question/28594409/answer/52835876
來源:知乎)
2、技術說明

技術上的問題,是將IO操做中等待和非等待的部分分開處理。咱們都知道IO操做分爲兩個部分:
一、等待數據就緒
二、處理數據多線程

 

衆所周知的幾種IO模型(阻塞、非阻塞、多路複用、信號驅動、異步)就是區別於這兩個階段,當須要處理不少鏈接的時候(高併發的狀況),容易想到的是使用多線程技術,好比最簡單的One-connection-Per-thread模式,可是由於等待數據不可避免,形成的結果是線程不停的休眠-喚醒的切換,致使CPU不堪重負。併發

IO複用的目的:將這兩個階段分開處理,讓一個線程(並且是內核級別的線程)來處理全部的等待,一旦有相應的IO事件發生就通知繼續完成IO操做,雖然仍然有阻塞和等待,可是等待老是發生在一個線程,這時使用多線程能夠保證其餘線程一旦喚醒就是處理數據,固然這須要非阻塞IO API的支持(好比非阻塞套接字)。Linux2.6以前的select,poll以及以後的epoll都是IO複用技術的實現。selectpoll基本一致,epoll是對它們的改進版本。但總的來講它們都還不是真正的異步IO,由於它們在IO讀寫的時候仍然是阻塞的、同步的(完成一件過後才能作另一件事)。異步IO是指「處理數據」這一階段也是非阻塞的。Windows上的IOCP(完成端口)纔是真正的AIO,理論上它比Linux的epoll更先進。框架

至於select、poll和epoll的區別,推薦這篇文章:http://www.cnblogs.com/Anker/p/3265058.html。簡單來講:select,poll無腦的輪詢,忽略了高併發下,輪詢自己成了瓶頸,而epoll使用回調實現了輪詢真正須要處理的鏈接。異步

 

Reactor模式是爲了咱們更簡單的使用IO複用技術。它是一種併發IO模式,其餘的模式還有多進程,多線程等。Reactor自己也有不少變種,好比thread per request,worker thread,thread pool,multiple reactors...網上這方面的資料不少。雖然網上關於reactor和多線程模孰優孰劣還有爭論(Reactor最明顯的一個缺點是沒法充分利用多核的優點),可是大部分高併發的框架或組建都是基於reactor的,好比MINA,Netty,再好比Redis,Nginx(有多個工做進程來充分利用多核的優點)。關於Java中的IO複用能夠看Doug Lea大神的Scalable IO in Java(http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf)。socket

相關文章
相關標籤/搜索