前言
作为一个服务器,肯定要满足多个客户端同时访问,在python中,可以有三种模型满足这种要求,分别是:循环服务模型、多进程/多线程模型,I/O并发模型。在这里,我们就探讨一下如何使用I/O多路复用实现I/O并发
I/O多路复用
定义:操作系统同时监控多个I/O,当哪个I/O准备就绪就执行哪个I/o,避免因为一个I/O阻塞而造成其他不相关I/O无法执行,提高效率
实现方式:python3中提供三种实现I/O多路复用的方式,分别是select,poll,epoll,总体来说,epoll的执行效率最高,且支持的I/O数量与poll持平都大于select,且支持边缘触发和水平触发两种方式
python3实现代码
通过select实现I/O多路复用
from select import select
from socket import socket
s = socket()
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind(('0.0.0.0', 9000))
s.listen(5)
rlist = [s]
wlist = []
xlist = []
while True:
rs, ws, xs = select(rlist, wlist, xlist)
for r in rs:
if r is s:
c, addr = s.accept()
rlist.append(c)
else:
data = r.recv(1024).decode()
print(data)
if not data:
c.close()
rlist.remove(r)
continue
wlist.append(r)
for w in ws:
w.send(b'OK')
ws.remove(w)
通过poll实现I/O多路复用
from socket import socket
from select import Poll
s = socket()
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind(('0.0.0.0', 9000))
s.listen(5)
p = Poll()
p.register(s,POLLIN|POLLOUT)
dic = {s.fileno(): s}
while True:
events = p.poll()
for filenumber, event in events:
if filenumber == s.fileno():
c, addr = s.accept()
p.register(c, POLLIN|POLLOUT)
dic[c.fileno()] = c
else:
data = dic[filenumber].recv(1024).decode()
if not data:
p.unregster(dic[filenumber])
dic[filenumber].close()
del dic[filenumber]
continue
dic[filenumber].send(b'ok')
通过epoll实现I/O多路复用
from socket import socket
from select import EPoll
s = socket()
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind(('0.0.0.0', 9000))
s.listen(5)
p = EPoll()
p.register(s,EPOLLIN|EPOLLOUT)
dic = {s.fileno(): s}
while True:
events = p.poll()
for filenumber, event in events:
if filenumber == s.fileno():
c, addr = s.accept()
p.register(c, EPOLLIN|EPOLLOUT)
dic[c.fileno()] = c
else:
data = dic[filenumber].recv(1024).decode()
if not data:
p.unregster(dic[filenumber])
dic[filenumber].close()
del dic[filenumber]
continue
dic[filenumber].send(b'ok')