進程| 線程 | 阻塞 | 阻塞&非阻塞 和 同步&異步

阻塞&非阻塞

阻塞IO數組

調用以後必定要等到系統內核完成全部的操做以後才結束,所以它的缺點:CPU等待IO,處理能力得不到充分利用。數據結構

非阻塞IO多線程

爲了解決阻塞IO帶來的一些問題,內核提供了非阻塞IO,非阻塞IO的差異是調用以後會當即返回。缺點:非阻塞IO當即返回並非業務層指望的數據,而僅僅是調用的狀態,爲了獲取完整的數據,應用程序須要重複調用IO操做確認,即輪詢。異步

輪詢線程

常見的三種輪詢方式:select、poll和epoll。進程

一、select事件

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

參數解釋資源

  • nfds:被監聽的文件描述符總數
  • readfds writefds exceptfds : 可讀、可寫、異常事件的accept到對應的文件描述符集合
  • fd_set:是一個整形數組,每個元素的每一位來表示每個文件描述符是否有相應的事件發生。(0沒有1有)數組的長度由FD_SETSIZE決定
  • timeout:輪詢的時間片

經過設置或者檢查存放fd(文件標識符)標誌位的數據結構進行處理(select對應於內核的sys_select調用):1.將第二、三、4個參數指向的fd_set拷貝到內核;2.對每一個被set對描述符調用進行poll,並記錄在臨時結果中(fdset)同步

缺點是:it

  • 單個進程的fd監視數量有限
  • 須要維護一個存放fd的數據結構,這樣會使得用戶空間和內核空間在傳遞該結構時複製開銷大
  • 每次select操做須要初始化fdset,由於select的第二、三、4參數既是輸入參數也是輸出參數,在內核中會被修改
  • socker的掃描是線性掃描

二、poll

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

poll和select的實現機制相似,對應內核的sys_poll,可是傳遞的是pollfd數組,接着對pollfd數組進行poll。

優勢:

  • pollfd數組只須要被初始化一次,由於pollfd的events字段和revents分別用於標示關注的事件和發生的事件
  • 對描述符個數沒有限制,poll經過一個pollfd數組向內核傳遞須要關注的事件

三、epoll

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

相對於select和poll的遍歷查詢,epoll是真實利用了執行回調和事件通知的機制,充分利用CPU,所以效率比較高。

四、總結

總的來講,輪詢技術知足非阻塞IO確保完整數據獲取的需求,當時對於應用程序來講,它仍然是同步,由於它必須等待IO徹底返回。等待IO期間,CPU要麼遍歷文件描述符的狀態,要沒用於休眠等待事件發生。

2、同步&異步

同步IO:同步IO比較簡單,就是簡單的順序執行,其實阻塞和非阻塞都屬於同步IO。

異步IO:這裏拿Node舉例,在Node中,咱們知道異步是它的一大特點,那它到底有哪些好處呢?

  • 一、從請求時間上來講,假設某個資源須要獲取a,b兩個地方的資源,a資源須要時間M毫秒,b資源須要時間N毫秒,此時:同步須要sum(M,N),異步須要max(M,N)
  • 2 從資源消耗來講,異步遠離阻塞,單線程避免了多線程容易出現的死鎖等各類異常狀況

咱們期待的異步是:當咱們應用程序發起阻塞請求,不須要輪詢技術,直接處理下一個任務;當阻塞請求完成以後,將數據傳遞到應用程序。在Linux下存在這種異步IO即AIO。

若是咱們本身去實現異步IO,則能夠經過線程池+輪詢技術來實現數據的獲取。例如如今應用程序發起了一個阻塞請求,咱們能夠以下處理:

  1. 讓a線程利用輪詢技術去處理阻塞調用
  2. 讓b線程去執行計算處理
  3. 當a線程的處理結果經過線程間共享發送給b
  4. 這樣,就完成了異步IO。

3、總結

經過上面的介紹,咱們須要知道的是:阻塞&非阻塞和異步&同步是不能混爲一談的,非阻塞本質上仍是同步,它所謂的返回只是狀態並非數據。

因爲阻塞&非阻塞和異步&同步的概念十分相似,這裏就其作了一個簡單介紹