在以前的博客中已經總結過度別在windows和linux操做系統下實現socket高併發(I/O異步)的方法,能夠參考基於epoll的TP傳輸層實現和Windows之IOCPhtml
下面對Python中實現socket高併發的selectors庫進行總結,官方參考文檔:https://docs.python.org/3/library/selectors.html python
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)
上面示例代碼來自官方文檔,接下來對關鍵代碼進行重點說明linux
(1)conn.setblocking(False)windows
設置socket的阻塞或非阻塞模式併發
阻塞模式下當試圖對該文件描述符進行讀寫時,若是當時沒有東西可讀,或者暫時不可寫,程序就進入等待狀態,直到有東西可讀或者可寫爲止異步
非阻塞模式下若是沒有東西可讀,或者不可寫,讀寫函數立刻返回,而不會等待socket
(2)sel.register(conn, selectors.EVENT_READ, read)函數
對描述符進行註冊,也就是對該描述符的EVENT_READ事件進行監聽,當又READ事件通知時,調用回調函數read高併發
selectors庫提供了兩個監聽事件:EVENT_READ和EVENT_WRITEpost
(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