python库之selectors
在之前的博客中已经总结过分别在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