精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

IO多路復用基本概念

科技綠洲 ? 來源:Linux開發架構之路 ? 作者:Linux開發架構之路 ? 2023-11-10 16:34 ? 次閱讀

一、IO多路復用基本概念

select、poll、epoll都是IO多路復用的機制。IO多路復用就是通過一種機制,讓一個進程/線程可以監視多個描述符,一旦某個描述符就緒(一般是讀寫就緒),能夠通知應用程序進行相應的讀寫操作。

I/O多路復用在英文叫 I/O multiplexing,這里面的 multiplexing 指的其實是在單個進程/線程通過記錄跟蹤每一個文件描述符的狀態來同時管理多個I/O流。發明它的原因,是盡可能地提高服務器的吞吐能力。

I/O復用雖然能同時監聽多個文件描述符,當其本質上還是同步IO模型,因為需要在讀寫事件就緒后程序自己負責進行讀寫事件的處理,而這個讀寫過程是阻塞的。如果要實現并發,只能使用多進程/多線程等編程手段了。與多進程/多線程技術相比,I/O多路復用技術最大的優勢就是系統開銷小,系統不必創建大量進程/線程,也不必維護這些進程/線程,從而大大減少了系統的開銷。

IO多路復用使用場景

1)當客戶處理多個描述符時(一般是交互式輸入和網絡接口),必須使用I/O復用。

2)當一個客戶同時處理多個套接口時,這種情況是可能的,但很少出現。

3)如果一個TCP服務器既要處理監聽套接口,又要處理已連接套接口,一般也要用到I/O復用。

4)如果一個服務器即要處理TCP,又要處理UDP,一般要使用I/O復用。

5)如果一個服務器要處理多個服務或多個協議,一般要使用I/O復用。

二、三組 I/O 多路復用函數的比較

這三組I/O多路復用系統調用都能同時監聽多個文件描述符。它們將等待由timeout參數指定的超時時間,直到一個或多個文件描述符上有事件發生時返回,返回值是就緒的文件描述符的數量,如果返回0,則表示沒有事件發生。

下面我們主要從事件集合、最大支持文件描述符數量、工作模式和底層實現原理等4個方面進一步比較它們的異同。

事件集合

這3組函數都通過某種結構體變量來告訴內核監聽哪些文件描述符上的哪些事件,并使用該結構體類型的參數來獲取內核的處理結果。

select:使用 fd_set 結構體來存放被監聽的文件描述符的,本質上是使用一個位圖結構來存放這些被監聽的文件描述符的,因此select能夠監聽的文件描述符數量是有限制的。同時,fd_set 沒有將文件描述符和事件進行綁定,它僅僅是一個文件描述符集合,因此,select需要提供3個fd_set類型的參數來分別傳入和傳出可讀、可寫及異常事件。一方面,使得select不能處理更多類型的事件,另一方面,由于內核對fd_set集合的在線修改,使得下次再調用select()函數前不得不重置這3個fd_set集合,這使得編程變成很麻煩,并且容易出錯。

poll:使用 struct pollfd結構體來存放被監聽的文件描述符,它比select“聰明”的地方就在于它把文件描述符和與其關聯的事件都定義在這個結構體中了,從而使得編程接口變得簡潔很多,同時內核每次修改的都是pollfd結構體的revents成員,而events成員保持不變,因此下次調用poll()函數時應用程序無須重置pollfd類型的事件集參數。

由于每次select 和 poll 調用都是返回整個用戶監聽的事件集合(其中包括就緒的和未就緒的),所以應用程序索引就緒文件描述符的時間復雜度為O(n)。

epoll:采用與select 和 poll 完全不同的方式來管理用戶注冊的事件。它在內核中維護一個事件表,并提供了一個獨立的系統調用函數 epoll_ctl來控制往該內核事件表中添加、刪除、修改事件。這樣,每次調用epoll_wait()函數時,都是直接從內核事件表中取得用戶注冊的事件,而無須反復從用戶空間將這些注冊事件讀入到內核區中,節省了復制的系統開銷。epoll_wait 系統調用中的 events 指針參數僅用來返回就緒的事件,這使得應用程序索引就緒文件描述符的時間復雜度為O(1)。需要注意的是,epoll 和 poll一樣,也是將文件描述符和與其關聯的事件是綁定在一起的,這樣做的好處是,編程接口變得簡潔,不像select那樣復雜。

最大支持文件描述符數量

poll 和 epoll 分別用 nfds 和 maxevents 參數指定最多監聽多少個文件描述符。這兩個數值都能達到系統允許打開的最大文件描述符數目,即 65 535(cat /proc/sys/fs/file-max)。而select允許監聽的最大文件描述符數量通常是有限的。雖然用戶可以修改這個限制,但是這可能會導致不可預期的后果。

工作模式

select 和 poll 都只能工作在相對低效的LT(水平觸發)模式,而epoll 雖然默認也是工作在LT模式下,但是它還可以工作在更高效的ET(邊緣觸發)模式下。并且 epoll 還支持 EPOLLONESHOT事件。該事件能進一步減少可讀、可寫和異常事件被觸發的次數。

底層實現原理

select 和 poll 都是采用輪詢的方式,即每次調用都要掃描整個注冊的文件描述符,并將其中就緒文件描述符的數量返回給應用程序,因此它們檢測就緒文件描述符的事件復雜度為O(n)。

而epoll則不同,它采用的是回調的方式,內核檢測到就緒的文件描述符時,將觸發回調函數,回調函數就將該文件描述符上對應的事件插入到內核就緒事件隊列。當調用epoll_wait 系統調用時,無須輪詢整個內核事件表中的文件描述符,而只需檢測就緒事件隊列是否有內容,如有,內核則將該就緒隊列中的內容拷貝到用戶空間,因此epoll檢測就緒文件描述符的時間復雜度為O(1)。

三、三組 I/O 多路復用的優缺點

3.1 select

【優點】

1、select的可移植性好,因為在某些Unix系統上并不支持poll 和 epoll(極少)。

2、select 對于超時時間提供了更好的精度:微秒,而 poll 和 epoll 都是毫秒級。

【缺點】

1、select 支持監聽的文件描述符fd的數量有限制,默認是1024個。(最大數量限制)

2、select 需要維護一個用來存放文件描述符fd的數據結構(fd_set),每次調用select都需要把fd集合從用戶區拷貝到內核區,而select系統調用結束后,又需要把fd集合從內核區拷貝到用戶區,這個系統開銷在fd數量很多時會很大。(內存復制開銷)

3、每次調用select系統調用時,都需要在內核遍歷傳入的整個文件描述符集合,逐個檢測,查看是否有就緒的文件描述符,然后返回就緒文件描述符的個數。也就是說,select對文件描述符是線性掃描的,當注冊的文件描述符fd的數量很多時,效率會較低,時間復雜度為O(n)。(時間復雜度)

3.2 poll

poll的實現原理和select非常相似,但是相比select,它做了一些改進的地方。首先是存放文件描述符的數據結構(pollfd),它將文件描述符和與其對應的事件關聯起來了,使得編程接口變得簡潔了;其次,它沒有了最大文件描述符的限制,原因是它是基于鏈表結構來存儲的。

【優點】(對比select而言)

1、沒有最大文件描述符數量的限制(相對select而言)。(基于鏈表存儲)poll 主要是解決了這個最大文件描述符數量的限制問題。

當然,它還是有上限的,這個上限是操作系統所支持的能開啟的最大文件描述符數量(cat /proc/sys/fs/file-max)。

2、優化了編程接口。select()函數有5個參數,而poll()減少到了3個參數。并且每次調用select函數前,都必須重置該函數中的3個fd_set類型的參數值,而poll不需要重置。

【缺點】

1、poll 同樣需要維護一個用來存放文件描述符的數據結構(pollfd),當注冊的文件描述符無數量很多時,會使得用戶區和內核區之間傳遞該數據結構的復制開銷很大。(內存復制開銷)

每次調用poll系統調用時,都需要把文件描述符fd集合從用戶區拷貝到內核區,然后poll系統調用返回前,又需要把文件描述符fd集合從內核區拷貝到用戶區,這個內存拷貝的系統開銷在fd數量很多的時候會很大。

<說明> 系統調用函數的執行是發生在內核區的,而用戶程序的執行是發生在用戶區的,所以會存在內核區與用戶區之間的內存復制的系統開銷。

2、與select一樣,每次poll系統調用時,需要在內核遍歷傳入的整個文件描述符集合,逐個檢測,查看是否有就緒的文件描述符,然后返回就緒文件描述符的個數。也就是說,poll也是線性掃描的方式,當注冊的文件描述符fd的數量很多時,效率會較低,時間復雜度為O(n)。(時間復雜度)

3、poll 只能工作在水平觸發(LT)模式下。(工作模式)

水平觸發模式下,當描述符處于就緒狀態下,內核通知了應用程序,但是應用程序沒有進行處理,那么下次調用poll時仍會向應用程序發出通知。

<注意> select 和 poll 都需要在返回后,通過遍歷整個文件描述符集合來獲取就緒的文件描述符。事實上,在網絡連接中,同時連接的大量客戶端在某一時刻可能只有很少的處于就緒狀態,因此隨著監視的描述符數量的遞增,其效率也會線性遞減。

3.3 epoll

epoll 是在Linux 2.6內核版本中提出的,是之前select和poll的增強版本。

epoll使用一個epoll文件描述符管理多個被監聽的文件描述符,將用戶關心的文件描述符的事件存放到內核的一個事件表中,這樣在用戶區和內核區只需要拷貝一次被監聽的文件描述符的數據結構(epoll_event)即可。

epoll 既解決了select的最大文件描述符數量限制的問題,又解決了poll的內存復制開銷大、時間復雜度大的問題(前提條件:文件描述符數量很大的情況下)。

【優點】(對比select和poll)

1、和poll一樣,沒有最大文件描述符數量的限制(相對select而言)。

2、epoll 雖然也需要維護用來存放文件描述符的數據結構(epoll_event),但是它只需要將該數據結構拷貝進內核區一次,不需要重復拷貝。

epoll只在調用 epoll_ctl 系統調用時拷貝一次要監聽的文件描述符數據結構到內核區,在調用 epoll_wait系統調用時不需要再把所有要監聽的文件描述符fd重復拷貝進內核區。而select和poll每次調用都需要把所有要監聽的fd重新拷貝到內核區。這就解決了內存復制開銷的問題。

3、epoll 采用回調方式來檢測就緒文件描述符。

epoll 通過epoll_ctl系統調用注冊一個文件描述符,一旦該文件描述符就緒,內核就會采用callback回調機制來進行通知,并將該就緒描述符放入就緒事件鏈表中。然后在epoll_wait系統調用中,當接收到有通知信號到來時,就會去檢測就緒事件鏈表是否有內容,如果有內容,就將就緒事件鏈表的內容從內核區拷貝到用戶區,最后epoll_wait系統調用返回就緒描述符的個數。也就是說,epoll只會對活躍的文件描述符進行管理,而不需要像select和poll那樣,每次調用都要線性掃描全部的文件描述符,導致效率呈現線性下降。

【缺點】

目前只有Linux操作系統支持epoll,不支持跨平臺使用。而Unix操作系統上是使用kqueue。

四、幾個需要注意的問題

4.1 用戶態將文件描述符參傳入內核的方式

  • select:創建3個文件描述符集的數據結構(fd_set)并拷貝到內核中,分別監聽讀、寫、異常事件。受單個進程/線程可以打開的文件描述符數量限制,默認是1024個文件描述符。
  • poll:將傳入的文件描述符數據結構(struct pollfd結構體數組)拷貝到內核中進行監聽。
  • epoll:執行epoll_create系統調用時會在內核的緩沖區中建立一顆紅黑樹以及就緒鏈表(該鏈表用于存儲已就緒的文件描述符)。接著用戶執行的epoll_ctl系統調用添加文件描述符,即在紅黑樹上增加相應的結點。

4.2 內核態檢測文件描述符就緒狀態的方式

  • select:采用輪詢方式,線性掃描所有用戶關注的文件描述符,如果檢測到某個文件描述符已就緒,就修改用戶傳進來的數據結構fd_set的值。
  • poll:同樣采用輪詢方式,線性掃描所有用戶關注的文件描述符,如果檢測到某個文件描述符就緒,內核就修改文件描述符fd對應的revents的值,并將其加入到內核的等待隊列中。
  • epll:采用回調方式。在執行epoll_ctl的ADD操作時,不僅將文件描述符放入紅黑樹上,并且還注冊了回調函數,如果某個文件描述符已就緒,它會主動調用回調函數,該回調函數將文件描述符放入到就緒鏈表中。

4.3 找到就緒文件描述符并傳遞給用戶態的方式

  • select:將之前傳入到內核態的數據結構(fd_set)重新拷貝傳出到用戶態,并返回就緒的文件描述符數量。但是用戶程序并不知道哪些文件描述符是處于就緒態,因此需要在用戶程序中對所有的文件描述符再一次進行遍歷來判斷。
  • poll:將之前傳入到內核態的數據結構(pollfd數組)重新拷貝傳出到用戶態,并返回就緒的文件描述符數量。用戶程序同樣不知道哪些文件描述符是處于就緒態,需要遍歷判斷。
  • epoll:epoll只需要檢測就緒事件鏈表中有無數據即可,如有,則只需將就緒鏈表的數據拷貝傳出到用戶態,并返回就緒的文件描述符數量。由于返回的就是就緒態的文件描述符,因此用戶程序不需要通過遍歷來判斷,而是直接處理即可。

4.4 重復監聽文件描述符的處理方式

  • select:將新的監聽文件描述符集合拷貝傳入內核中,繼續以上步驟。
  • poll:將新的struct pollfd結構體數組拷貝傳入內核中,繼續以上步驟。
  • epoll:無需重新構建紅黑樹,直接沿用已存在的即可。

4.5 三種IO多路復用的適用場景

select、poll:適合在連接數少并且連接都十分活躍的情況下。

epoll:適用在連接數很多,活躍連接較少的情況下。

表面上看epoll的性能最好,但是在連接數少并且連接都十分活躍的情況下,select和poll的性能可能比epoll要好,畢竟epoll的通知機制需要調用很多的函數回調,這也是一筆不小的系統開銷。
select、poll的低效是因為每次它們都需要輪詢。但低效也是相對的,視情況而定,也可通過良好的設計改善。

五、總結

  • select,poll,epoll都是IO多路復用的實現機制。它們本質上還是同步IO,而不是異步IO,因為它們都需要在讀寫事件就緒后自己負責進行讀寫操作,而這個讀寫過程是阻塞的;而異步I/O則無需自己負責進行讀寫,異步I/O的實現會負責把數據從內核空間拷貝到用戶空間。
  • select、poll的底層實現中需要自己不斷地輪詢所有fd集合,直到文件描述符就緒,期間可能要睡眠和喚醒多次交替。而epoll其實也需要調用 epoll_wait 不斷輪詢就緒鏈表,期間也可能多次睡眠和喚醒交替,但是它是當某個文件描述符就緒時,主動調用回調函數,把就緒的文件描述符放入就緒鏈表中,并喚醒在epoll_wait中進入睡眠的進程。雖然都要睡眠和交替,但是select和poll在“醒著”的時候要遍歷整個fd集合,而epoll在“醒著”的 時候只須判斷一下就緒鏈表是否為空就行了,這就節省了大量的CPU時間,這就是回調機制帶來的性能提升。
  • select、poll每次調用(調用select()、poll()函數)都要把所有文件描述符fd集合從用戶態拷貝到內核態,而epoll是在初始調用epoll_create時在內核區先開辟好緩存區,然后在調用epoll_ctl時,將待注冊的文件描述符從用戶態拷貝到內核態,并且只需要拷貝這一次,在每次調用epoll_wait時,不再需要重復拷貝,這就節省了內存復制帶來的系統開銷。

為了便于閱讀,我們將這3組I/O多路復用的系統調用的區別總結成一個圖表,如下圖所示:

圖片

select、poll 和 epoll的區別

六、面試題

1、在epoll IO多路復用中,某個socket讀到一半,在這個socket上又有讀事件來了怎么辦?

答:為了避免在同一個socket上再次監聽到同一個可讀事件,可以在對應的描述符中添加 EPOLL_ONESHOT事件,其效果是監聽到一次事件后就將對應的描述符從監聽集合中移除,也就不會再被追蹤到了。讀操作完成后再把對應的文件描述符重新加入監聽集合。

2、LT和ET模式下的阻塞與非阻塞?

答:在ET(水平觸發)模式下,也是epoll的默認模式,epoll_wait返回可讀事件,表明socket一定收到了數據,我們可以使用read函數來讀取數據。如果指定讀取的數據大于緩沖區數據,無論socket是阻塞還是非阻塞,read函數不會阻塞,會返回實際讀取到的數據大小。在read之后再次調用read,如果socket是阻塞的,read將阻塞,直到接收到數據才返回。此時,如果指定讀取的數據小于緩沖區中數據,epoll_wait 會繼續被觸發,因為還有讀緩沖區中還有數據沒有被讀取完。

在ET(邊緣觸發)模式下,只有新的數據到來時才會觸發。如果指定讀取的數據小于緩沖區中的數據,epoll_wait 不會被繼續觸發。因此,使用ET模式時,有數據到來時,必須循環讀取讀緩沖區中的數據,直到read返回-1,并且errno錯誤碼為EAGAIN,才算讀取完了全部緩沖區中的內容。

  • 對于監聽的listen_fd,最好使用LT模式,如果使用ET模式會導致高并發情況下,有的客戶端會連接不上。如果非要使用ET模式,可以在while循環中調用accept()函數。
  • 對于讀寫的conn_fd,LT模式下,阻塞和非阻塞效果都一樣,因為在阻塞模式下,如果數據讀取不完全則返回繼續觸發,反之讀取完則返回繼續等待。建議將文件描述符設置為非阻塞。
  • 對于讀寫的conn_fd,ET模式下,必須使用非阻塞IO,并要求一次性地完整讀寫完全部數據。因為如果不一次性讀取完緩沖區中的全部數據,緩沖區剩余數據不會被 epoll_wait 再次觸發。
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • IO
    IO
    +關注

    關注

    0

    文章

    418

    瀏覽量

    38881
  • 參數
    +關注

    關注

    11

    文章

    1661

    瀏覽量

    31878
  • UDP
    UDP
    +關注

    關注

    0

    文章

    317

    瀏覽量

    33801
  • 編程接口
    +關注

    關注

    1

    文章

    36

    瀏覽量

    7971
收藏 人收藏

    評論

    相關推薦

    [6.4.1]--多路復用

    多路復用數字邏輯
    李開鴻
    發布于 :2022年11月13日 01:18:45

    一節課了解IO多路復用-2021.8.31-大海老師 - 第1節 #硬聲創作季

    IO多路復用
    充八萬
    發布于 :2023年09月01日 21:27:46

    一節課了解IO多路復用-2021.8.31-大海老師 - 第7節 #硬聲創作季

    IO多路復用
    充八萬
    發布于 :2023年09月01日 21:32:48

    一節課了解IO多路復用-2021.8.31-大海老師 - 第8節 #硬聲創作季

    IO多路復用
    充八萬
    發布于 :2023年09月01日 21:33:38

    一節課了解IO多路復用-2021.8.31-大海老師 - 第9節 #硬聲創作季

    IO多路復用
    充八萬
    發布于 :2023年09月01日 21:34:29

    一節課了解IO多路復用-2021.8.31-大海老師 - 第10節 #硬聲創作季

    IO多路復用
    充八萬
    發布于 :2023年09月01日 21:35:19

    一節課了解IO多路復用-2021.8.31-大海老師 - 第13節 #硬聲創作季

    IO多路復用
    充八萬
    發布于 :2023年09月01日 21:37:50

    多路復用技術

    2.3  多路復用技術2.3.1  頻分多路復用2.3.2  時分多路復用2.3.3  波分多路復用2.3.4  碼分
    發表于 06-27 21:46 ?0次下載

    多路復用多路復用總線轉換橋的設計與實現

    多路復用多路復用總線轉換橋的設計與實現 提出了一種新穎的非多路復用總線與多路復用總線的轉換接口電路。以兩種總線的典型代表芯片TMS
    發表于 03-28 15:14 ?914次閱讀
    非<b class='flag-5'>多路復用</b>與<b class='flag-5'>多路復用</b>總線轉換橋的設計與實現

    復用器的多路復用

    復用器的多路復用  多路復用
    發表于 01-07 14:27 ?1166次閱讀

    時分多路復用(TDM),時分多路復用(TDM)的原理是什么?

    時分多路復用(TDM),時分多路復用(TDM)的原理是什么?  為了提高信道利用率,使多個信號沿同一信道傳輸而互相不干擾,稱
    發表于 03-19 14:07 ?1w次閱讀

    時分多路復用(TDM),時分多路復用(TDM)是什么意思

    時分多路復用(TDM),時分多路復用(TDM)是什么意思 這種方法是把傳輸信道按時間來分割,為每個用戶指定一個時間間隔,每個間隔里傳輸信號
    發表于 04-03 15:28 ?5737次閱讀

    網絡IO的弊端以及多路復用IO的優勢

    為了講多路復用,當然還是要跟風,采用鞭尸的思路,先講講傳統的網絡 IO 的弊端,用拉踩的方式捧起多路復用 IO 的優勢。 為了方便理解,以下所有代碼都是偽代碼,知道其表達的意思即可。
    的頭像 發表于 08-25 18:01 ?2750次閱讀
    網絡<b class='flag-5'>IO</b>的弊端以及<b class='flag-5'>多路復用</b><b class='flag-5'>IO</b>的優勢

    掌握多片FPGA的多路復用

    多片FPGA之間的互連,經常提到多路復用概念,也經常提到TDM的概念
    發表于 06-06 10:07 ?307次閱讀
    掌握多片FPGA的<b class='flag-5'>多路復用</b>

    什么是io多路復用IO多路復用的優缺點

    IO多路復用是一種同步IO模型,它允許單個進程/線程同時處理多個IO請求。具體來說,一個進程/線程可以監視多個文件句柄,一旦某個文件句柄就緒,就能夠通知應用程序進行相應的讀寫操作。在沒
    的頭像 發表于 01-18 15:48 ?1401次閱讀