1. 程式人生 > >python庫之selectors 基於epoll的TP傳輸層實現和 Windows之IOCP

python庫之selectors 基於epoll的TP傳輸層實現和 Windows之IOCP

  在之前的部落格中已經總結過分別在windows和linux作業系統下實現socket高併發(I/O非同步)的方法,可以參考基於epoll的TP傳輸層實現Windows之IOCP

  下面對Python中實現socket高併發的selectors庫進行總結,官方參考文件:https://docs.python.org/3/library/selectors.html 

1. 示例程式碼

import selectors
import socket

sel = selectors.DefaultSelector()

def accept(sock, mask):
    conn, addr 
= sock.accept() # Should be ready print('accepted', conn, 'from', addr) conn.setblocking(False) sel.register(conn, selectors.EVENT_READ, read) def read(conn, mask): data = conn.recv(1000) # Should be ready if data: print('echoing', repr(data), 'to', conn) conn.send(data) # Hope it won
't block else: print('closing', conn) sel.unregister(conn) conn.close() sock = socket.socket() sock.bind(('localhost', 1234)) sock.listen(100) sock.setblocking(False) sel.register(sock, selectors.EVENT_READ, accept) while True: events = sel.select() for key, mask in
events: callback = key.data callback(key.fileobj, mask)

   上面示例程式碼來自官方文件,接下來對關鍵程式碼進行重點說明

2. 重點知識說明

(1)conn.setblocking(False)

  設定socket的阻塞或非阻塞模式

  阻塞模式下當試圖對該檔案描述符進行讀寫時,如果當時沒有東西可讀,或者暫時不可寫,程式就進入等待狀態,直到有東西可讀或者可寫為止

  非阻塞模式下如果沒有東西可讀,或者不可寫,讀寫函式馬上返回,而不會等待

(2)sel.register(conn, selectors.EVENT_READ, read)

  對描述符進行註冊,也就是對該描述符的EVENT_READ事件進行監聽,當又READ事件通知時,呼叫回撥函式read

  selectors庫提供了兩個監聽事件:EVENT_READ和EVENT_WRITE

(3)sel.unregister(conn)

  登出描述符

(4)events = sel.select()

  函式原型為:abstractmethod select(timeout=None)

  該函式是實現I/O非同步的關鍵,等待,直到一些已註冊的檔案物件準備就緒,或者超時。

  如果timeout>0,則指定最大等待時間,以秒為單位,如果超時沒有,則呼叫將阻塞,直到被監視的檔案物件準備就緒。如果timeout< 0,呼叫將不會阻塞,並將報告當前就緒的檔案物件。

  該函式返回一個元組(key, events)

  key為class selectors.SelectorKey物件,SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data'])

  fileobj為註冊的檔案物件

  fd為檔案描述符

  data為與檔案物件相關聯的自定義資料,如上面的回撥函式

  明確上面的4個知識點後會覺得selectors庫的使用很簡單

  最後對DefaultSelector進行說明,DefaultSelector會根據當前作業系統型別自己選擇selector型別

if 'KqueueSelector' in globals():
    DefaultSelector = KqueueSelector
elif 'EpollSelector' in globals():
    DefaultSelector = EpollSelector
elif 'DevpollSelector' in globals():
    DefaultSelector = DevpollSelector
elif 'PollSelector' in globals():
    DefaultSelector = PollSelector
else:
    DefaultSelector = SelectSelector