Python學習之路 30 IO多路復用

2022-08-27 00:21:17 字數 3926 閱讀 2445

io多路復用是指核心一旦發現程序指定的乙個或者多個io條件準備讀取,它就通知該程序。

舉例說明

你是一名老師(執行緒),上課了(啟動執行緒),這節課是自習課,學生都在自習,你也在教室裡面坐著,只看著這幫學生,什麼也不幹(休眠狀態),課程進行到一半時,a同學(socket)突然拉肚子,舉手說:老濕我要上廁所(read),然後你就讓他去了,過了一會,b同學(socket)在自習的過程中有個問題不太懂,就請你過去幫她解答下(write),然後你就過去幫他解答了。

上述這種情況就是io多路復用,你就是乙個io,那麼你解決了a同學的問題和b同學的問題,這就是復用,多路網路連線復用乙個io執行緒。

與多程序和多執行緒技術相比,i/o多路復用技術的最大優勢是系統開銷小,系統不必建立程序/執行緒,也不必維護這些程序/執行緒,從而大大減小了系統的開銷。

目前常見支援i/o多路復用的系統呼叫有 select,poll,epoll,i/o多路復用就是通過一種機制,乙個程序可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程式進行相應的讀寫操作

select 監視的檔案描述符分3類,分別是writefds、readfds和exceptfds,程式啟動後select函式會阻塞,直到有描述符就緒(有資料 可讀、可寫、或者有except),或者超時(timeout指定等待時間,如果立即返回設為null即可),函式返回,當select函式返回後,可以通過遍歷fdset,來找到就緒的描述符。

select最大的缺陷就是單個程序所開啟的fd是有一定限制的,它由fd_setsize設定,預設值是1024;

對socket進行掃瞄時是線性掃瞄,即採用輪詢的方法,效率較低;

需要維護乙個用來存放大量fd的資料結構,這樣會使得使用者空間和核心空間在傳遞該結構時複製開銷大;

python實現select模型**

#!/usr/bin/env python

# _*_coding:utf-8 _*_

import select

import socket

sk1 = socket.socket()

sk1.bind(('127.0.0.1', 8002, ))

sk1.listen()

demo_li = [sk1]

outputs =

message_dict = {}

while true:

r_list, w_list, e_list = select.select(sk1, outputs, , 1)

print(len(demo_li),r_list)

for sk1_or_conn in r_list:

if sk1_or_conn == sk1:

conn, address = sk1_or_conn.accept()

message_dict[conn] =

else:

try:

data_bytes = sk1_or_conn.recv(1024)

# data_str = str(data_bytes, encoding="utf-8")

# print(data_str)

# sk1_or_conn.sendall(bytes(data_str+"good", encoding="utf-8"))

except exception as e:

demo_li.remove(sk1_or_conn)

else:

data_str = str(data_bytes, encoding="utf-8")

for conn in w_list:

recv_str = message_dict[conn][0]

del message_dict[conn][0]

conn.sendall(bytes(recv_str+"good", encoding="utf-8"))

outputs.remove(conn)

基本原理:

poll本質上和select沒有區別,它將使用者傳入的陣列拷貝到核心空間,然後查詢每個fd對應的裝置狀態,如果裝置就緒則在裝置等待佇列中加入一項並繼續遍歷,如果遍歷完所有fd後沒有發現就緒裝置,則掛起當前程序,直到裝置就緒或者主動超時,被喚醒後它又要再次遍歷fd。這個過程經歷了多次無謂的遍歷。

它沒有最大連線數的限制,原因是它是基於鍊錶來儲存的,但是同樣有乙個缺點:

大量的fd的陣列被整體複製於使用者態和核心位址空間之間,而不管這樣的複製是不是有意義。

poll還有乙個特點是「水平觸發」,如果報告了fd後,沒有被處理,那麼下次poll時會再次報告該fd。

poll是在2.6核心中提出的,是之前的select和poll的增強版本。相對於select和poll來說,epoll更加靈活,沒有描述符限制。epoll使用乙個檔案描述符管理多個描述符,將使用者關係的檔案描述符的事件存放到核心的乙個事件表中,這樣在使用者空間和核心空間的copy只需一次。

基本原理:

epoll支援水平觸發和邊緣觸發,最大的特點在於邊緣觸發,它只告訴程序哪些fd剛剛變為就緒態,並且只會通知一次。還有乙個特點是,epoll使用「事件」的就緒通知方式,通過epoll_ctl註冊fd,一旦該fd就緒,核心就會採用類似callback的**機制來啟用該fd,epoll_wait便可以收到通知。

epoll的優點:

沒有最大併發連線的限制,能開啟的fd的上限遠大於1024(1g的記憶體上能監聽約10萬個埠)。

效率提公升,不是輪詢的方式,不會隨著fd數目的增加效率下降。只有活躍可用的fd才會呼叫callback函式;即epoll最大的優點就在於它只管你「活躍」的連線,而跟連線總數無關,因此在實際的網路環境中,epoll的效率就會遠遠高於select和poll。

記憶體拷貝,利用mmap()檔案對映記憶體加速與核心空間的訊息傳遞;即epoll使用mmap減少複製開銷。

epoll對檔案描述符的操作有兩種模式:lt(level trigger)和et(edge trigger)。lt模式是預設模式,lt模式與et模式的區別如下:

lt模式:當epoll_wait檢測到描述符事件發生並將此事件通知應用程式,應用程式可以不立即處理該事件。下次呼叫epoll_wait時,會再次響應應用程式並通知此事件。

et模式:當epoll_wait檢測到描述符事件發生並將此事件通知應用程式,應用程式必須立即處理該事件。如果不處理,下次呼叫epoll_wait時,不會再次響應應用程式並通知此事件。

lt模式 lt(level triggered)是預設的工作方式,並且同時支援block和no-block socket。在這種做法中,核心告訴你乙個檔案描述符是否就緒了,然後你可以對這個就緒的fd進行io操作。如果你不作任何操作,核心還是會繼續通知你的。

et模式 et(edge-triggered)是高速工作方式,只支援no-block socket。在這種模式下,當描述符從未就緒變為就緒時,核心通過epoll告訴你。然後它會假設你知道檔案描述符已經就緒,並且不會再為那個檔案描述符傳送更多的就緒通知,直到你做了某些操作導致那個檔案描述符不再為就緒狀態了(比如,你在傳送,接收或者接收請求,或者傳送接收的資料少於一定量時導致了乙個ewouldblock 錯誤)。但是請注意,如果一直不對這個fd作io操作(從而導致它再次變成未就緒),核心不會傳送更多的通知(only once)。et模式在很大程度上減少了epoll事件被重複觸發的次數,因此效率要比lt模式高。epoll工作在et模式的時候,必須使用非阻塞套介面,以避免由於乙個檔案控制代碼的阻塞讀/阻塞寫操作把處理多個檔案描述符的任務餓死。

在select/poll中,程序只有在呼叫一定的方法後,核心才對所有監視的檔案描述符進行掃瞄,而epoll事先通過epoll_ctl()來註冊乙個檔案描述符,一旦基於某個檔案描述符就緒時,核心會採用類似callback的**機制,迅速啟用這個檔案描述符,當程序呼叫epoll_wait()時便得到通知。(此處去掉了遍歷檔案描述符,而是通過監聽**的的機制。這正是epoll的魅力所在。)

Java的學習之路 io流

io流 作用io流用來處理裝置與程式之間的資料傳輸 分類按流向 輸入流輸出流 按處理的單位 位元組流8bit byte 字元流16bit char 按流的角色 節點流 檔案流 直接傳輸 處理流 封裝 與節點流相比效率更高 常用的io流 file類 代表與平台無關的檔案或目錄 能新建 刪除 重新命名檔...

python多執行緒函式 python之路 多執行緒

1 多執行緒模組 import threading 2 用函式寫乙個多執行緒例子 import threading,time def talk name print name,is tlaking threading.current thread threading.active count tim...

Python學習之路

python 十分鐘入門 python 菜鳥教程 pycharm安裝numpy python 檔案讀取 with open xml path,r as fr content fr.read python讀取檔案時提示 unicodedecodeerror gbk codec can t decode...