1. 程式人生 > >IO模型

IO模型

selector 經歷 mask roc key multiple recv error 模型

IO模型:

  對於一個network IO(這裏我們以read舉例),它會涉及到兩個系統對象,一個是調用這個IO的process(or Thread),另一個就是系統內核(kernel),當一個read操作發生時,它會經歷兩個階段:

  1.等待數據準備()

  2.將數據從內核拷貝到進程中

blocking IO(阻塞IO):

  blocking IO的特點就是在IO執行的兩個階段都被block了.

non-blocking IO(非阻塞IO):

  非阻塞的recvfrom系統調用之後,進程並沒有被阻塞,內核馬上返回給進程,如果數據還沒有準備好,此時會返回一個error.進程在返回之後,可以幹點別的事情,然後再發起recvfrom系統調用.循環往復的進行recvfrom系統調用,這個過程被稱之為輪詢,輪詢檢查內核數據,直到數據準備好,再拷貝數據到進程,進行數據處理.拷貝數據整個過程,進程仍然是處於阻塞狀態.

  優點:能夠在等待任務完成的時間裏幹其他活了(也就是後臺,可以有多個任務在同時執行)

  缺點:任務完成的響應延遲增大了,因為每過一段時間才去輪詢一次read操作,而任務可能在兩次輪詢之間的任意時間完成.這會導致整體數據吞吐量的降低.

IO multiplexing(IO多路復用):

  select函數返回結果中如果有文件可讀了,那麽進程就可以通過調用accept()或recv()來讓kernel將位於內核中準備到的數據copy到用戶區.

  select的優勢在於可以處理多個鏈接,不適用於單個鏈接

selectors模塊:

 1 import selectors
 2 import socket
3 4 sel = selectors.DefaultSelector() 5 6 def accept(sock, mask): 7 conn, addr = sock.accept() # Should be ready 8 print(accepted, conn, from, addr) 9 conn.setblocking(False) 10 sel.register(conn, selectors.EVENT_READ, read) 11 12 def read(conn, mask): 13 data = conn.recv(1000) #
Should be ready 14 if data: 15 print(echoing, repr(data), to, conn) 16 conn.send(data) # Hope it won‘t block 17 else: 18 print(closing, conn) 19 sel.unregister(conn) 20 conn.close() 21 22 sock = socket.socket() 23 sock.bind((localhost, 1234)) 24 sock.listen(100) 25 sock.setblocking(False) 26 sel.register(sock, selectors.EVENT_READ, accept) 27 28 while True: 29 events = sel.select() 30 for key, mask in events: 31 callback = key.data 32 callback(key.fileobj, mask)

IO模型