selectors 模塊
它的功能與 linux 的 epoll,還是 select 模塊, poll 等類似;
實現高效的 I/O multiplexing , 常用於非阻塞的 socket 的編程中
官方文檔
內部類
▤ BaseSelector
▧ SelectSelector
▧ PollSelector
▧ EpollSelector
▧ DevpollSelector
▧ KqueueSelector
▤ DefaultSelector
實際使用為此類, 自動選擇為當前環境中最有效的 Selector ,
所以平時用 DefaultSelector 類就可以了,其它用不着
定義事件類型
▤ EVENT_READ - 表示可讀
▤ EVENT_WRITE - 表示可寫
SelectorKey類
模塊定義了一個 SelectorKey 類, 一般用這個類的實例 來描述一個已經注冊的文件對象的狀態, 這個類的幾個屬性常用到:
▤ fileobj - 表示已經注冊的文件對象;
▤ fd - 表示文件對象的描述符,是一個整數,它是文件對象的 fileno() 方法的返回值;
▤ events - 表示注冊一個文件對象時,我們等待的 events , 即上面的 event Mask , 是可讀呢還是可寫呢!!
▤ data - 表示注冊一個文件對象是邦定的 data ;
常用方法
register(fileobj, events, data=None)
作用
注冊一個文件對象。
參數
fileobj 即可以是fd 也可以是一個擁有 fileno() 方法的對象;
events上面的 event Mask 常量 data
返回值
一個 SelectorKey 類的實例
unregister(fileobj)
作用
注銷一個已經注冊過的文件對象;
返回值
一個 SelectorKey 類的實例
modify(fileobj, events, data=None)
作用
用於修改一個注冊過的文件對象,比如從監聽可讀變為監聽可寫
它其實就是 register() 后再跟 unregister()
但是使用 modify() 更高效
返回值
一個 SelectorKey 類的實例
select(timeout=None)
作用
用於選擇滿足我們監聽的 event 的文件對象
返回值
是一個 (key, events) 的元組,
其中 key 是一個 SelectorKey 類的實例,
而 events 就是 event Mask ( EVENT_READ 或 EVENT_WRITE ,或者二者的組合)
close()
作用
關閉 selector
最后一定要記得調用它, 要確保所有的資源被釋放;
get_key(fileobj)
作用
返回注冊文件對象的 key ;
返回值
一個 SelectorKey 類的實例;
實例
官方實例
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)
易懂實例
#!/usr/bin/python import selectors import socket # selectors模塊默認會用epoll,如果你的系統中沒有epoll(比如windows)則會自動使用select sel = selectors.DefaultSelector() # 生成一個select對象 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) # 新連接注冊read回調函數 def read(conn, mask): data = conn.recv(1024) # Should be ready if data: print('echoing', repr(data), 'to', conn) conn.send(data) else: print('closing', conn) sel.unregister(conn) conn.close() sock = socket.socket() sock.bind(('localhost', 8080)) sock.listen() sock.setblocking(False) sel.register(sock, selectors.EVENT_READ, accept) # 把剛生成的sock連接對象注冊到select連接列表中,並交給accept函數處理 while True: events = sel.select() # 默認是阻塞,有活動連接就返回活動的連接列表 # 這里看起來是select,其實有可能會使用epoll,如果你的系統支持epoll,那么默認就是epoll for key, mask in events: callback = key.data # 去調accept函數 callback(key.fileobj, mask) # key.fileobj就是readable中的一個socket連接對象