高性能服務器————高性能服務器之IO複用

1.爲什麼要使用IO複用?
在很多文章中都能夠看到IO複用的講解但是很少看到過,對IO複用使用原因的講解,和應用場景的說明。
(1)在不使用線程的情況下,獨立處理每個文件描述符,單個進程無法同時在多個文件描述符上阻塞,只有在這些描述符處於就緒狀態(關於就緒狀態,下文會說明)時,才能進行對文件描述符的操作(IO操作),否則會導致進程阻塞在IO操作上(此處的IO均爲阻塞IO)。例如:發送了read()調用,但是還沒有數據可讀,此時進程阻塞,無法對其他文件描述符提供服務。
(2)文件描述符與IO總是關聯的(如:管道描述符和管道的IO操作是關聯的),此時對文件描述符的監控將更有利於處理IO操作,提高效率。
(3)就網絡應用程序而言,可能同時打開多個文件描述符(這裏指socket),當一個socket處於阻塞時,後續的socket也無法獲取到服務(單線程/單進程)。
注意:
上述的原因都是基於單線程、單進程和阻塞IO的,那麼可以通過多線程、多進程、非阻塞IO來替代,不過IO複用有點也是它們無法替代的,這就取決與應用場景了。
IO複用對比與非阻塞IO:
非阻塞IO:應用發送IO請求時,使用非阻塞IO便會立即返回,而不是阻塞,此時只需要做連續隨機發送IO操作,直到某個打開的文件描述符可以執行IO操作。
形如:

int fd = open(.....);
//連續隨機發送IO操作
while(1)
{
	int read_sz = read(fd,buf,1024);
	if(read_sz>0)
		break;
}

IO複用:將所有關心的文件描述符集中處理,並將文件描述以及關心的事件監控起來,此時,如果文件描述符沒有發生改變(處於有緒狀態)時,進程處於睡眠狀態,當有一個或多個文件描述符發生改變(可進行IO操作)時,喚醒進程。
非阻塞IO與IO複用的對比:
非阻塞:採用連續隨機發送IO操作,cpu資源未釋放
IO複用:採用進程睡眠的方式,當有文件描述符發生狀態改變時,喚醒進程。對於進程睡眠階段,cpu資源是釋放了的
從這個角度來對比,IO複用是有必要的,而且能夠更好的利用cpu資源,此外cpu資源的寶貴就不用多說了。
多線程、多進程與IO複用的對比:
僅從一點便可知曉IO複用的必要性,1.進程的開銷就不必多說了,而IO複用的開銷還是相對較小的;2.線程雖比進程的開銷較小一點,但總歸還是比較於IO複用要大一點。3.線程和進程的創建是有上限的,而IO複用在單線程單進程的情況下便能夠處理,當要對更多的文件描述符提供服務時,僅憑多進程、多線程的一己之力是不夠的,此時結合IO複用就呢能夠更好的解決問題。總之,到底使用那個解決方案會更好點,哪得要根據具體的情況,具體分析,這裏就不再贅言了。
2.什麼是IO複用?
相信通過上面的介紹我們對IO複用有了一定的瞭解,那麼我們在這就說說什麼是IO複用吧。
IO複用: 同時監控(監聽)多個文件描述符,只將這些文件描述符中發生狀態改變的(處於就緒狀態的,關於就緒,下面會細說)的文件描述符返回給用戶,有用戶來對這些文件描述符進行IO操作。
文件描述符處於就緒狀態的條件:
就緒:即文件描述符可讀、可寫或出現異常。
以下以socket爲例:
socket可讀的情況:
1.socket的內核接收緩衝區中字節數大於或等於低水位標誌SO_RCVLOWAT時,進程可以無阻塞的讀,並且read返回值大於0。
2.socket通信對端關閉連接。socket讀返回0。
3.socket上有新連接請求。
4.socket上有未處理的錯誤。
socket可寫的情況:
1.socket的內核發送緩衝區中字節數大於或等於低水位標誌SO_SNDLOWAT時,進程可以無阻塞的寫,並且write返回值大於0。
2.socket的寫操作被關閉,執行寫操作觸發一個SIGPIPE信號。
3.socket使用非阻塞connect連接失敗、成功或超時之後。
4.socket上有未處理的錯誤。
**低水位標誌:**實質是一個觸發可讀/可寫的標準(或者說約定),假設接收的低水位標誌爲64個字節,那麼接收緩衝區有64個字節(或大於),此時描述符就緒(可讀)。
3.IO複用的應用場景:
1.客戶端程序需要同時處理多個socket。如:非阻塞的connect請求。
2.客戶端程序要同時處理用戶輸入和網絡連接。
3.服務器同時處理TCP和UDP請求。
4.服務器要監聽多個端口,或處理多種服務。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章