IO模型 ---io多路复用(三)
两者相互比较
1、如果只有一个用户连接server端,多路复用IO还不如阻塞IO效率高
2、相比阻塞IO,多路复用IO中间多了个反馈机制
3、多路复用IO的代码可以同时监控socket、多个socket对象coon1 coon2....、 recv
4、多路复用IO可以识别有人连接某个coon3,然后告知有coon3,然后coon3 recv
5、可以不用while turn(占内存)去循环监听,直接有个代替我去做这些事
6、多路复用IO机制是操作系统提供的,不是代码级别的,win下有专门提供多路复用IO机制select模块来完成【代理】的服务
io多路复用
server端
import select
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8000))
sk.setblocking(False)
sk.listen()
read_lst = [sk]
while True: # [sk,conn]
r_lst,w_lst,x_lst = select.select(read_lst,[],[])
for i in r_lst:
if i is sk:
conn,addr = i.accept()
read_lst.append(conn)
else:
ret = i.recv(1024)
if ret == b'':
i.close()
read_lst.remove(i)
continue
print(ret)
i.send(b'goodbye!')
client端
import time
import socket
import threading
def func():
sk = socket.socket()
sk.connect(('127.0.0.1',8000))
sk.send(b'hello')
time.sleep(3)
print(sk.recv(1024))
sk.close()
for i in range(20):
threading.Thread(target=func).start()
这种并发是使用IO多路复用机制来实现并发的socket的server,并不是牺牲CPU的使用率来实现的,而是利用操作系统提供的IO多路复用的机制
# IO多路复用(在win下并不是很高效)
# select机制 Windows 和 linux 都有 都是操作系统轮询每一个被监听的项,看是否有读操作
# poll机制 linux 它可以监听的对象比select机制可以监听的多
# 随着监听项的增多,导致效率降低
# epoll机制 linux 对每一个列表监听的对象绑定一个回调函数,回调函数来反馈有人来链接(Linux下推荐使用)
为了代码的可用于适用不同系统机制,出现selector,根据系统自动选择对于的IO多路复用机制(selector_demo)
import selectors
from socket import *
def accept(sk,mask):
conn,addr=sk.accept()
sel.register(conn,selectors.EVENT_READ,read)
def read(conn,mask):#一般使用我们只需要变动这段内容就好,其他不用变
try:
data=conn.recv(1024)
if not data:
print('closing',conn)
sel.unregister(conn)
conn.close()
return
conn.send(data.upper()+b'_SB')
except Exception:
print('closing', conn)
sel.unregister(conn)
conn.close()
sk=socket()
sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
sk.bind(('127.0.0.1',8088))
sk.listen(5)
sk.setblocking(False) #设置socket的接口为非阻塞
sel=selectors.DefaultSelector() # 选择一个适合我的IO多路复用的机制
sel.register(sk,selectors.EVENT_READ,accept)
#相当于网select的读列表里append了一个sk对象,并且绑定了一个回调函数accept
# 说白了就是 如果有人请求连接sk,就调用accept方法
while True:
events=sel.select() #检测所有的sk,conn,是否有完成wait data阶段,这里没SK对象是阻塞,当有SK对象时走下面的for
for sel_obj,mask in events: # [SK] [conn]
callback=sel_obj.data #callback=read
callback(sel_obj.fileobj,mask) #read(conn,1)
站在python角度,不太好实现异步框架,因为在copy date阶段未提供对于python接口
当我们web开发server端时,如果预计可能每秒的访问量比较大时,这时候我们就不要选择diango框架(非异步框架),应该选择 tornade(或 twstied)异步IO框架(没有wait date和copy date阻塞阶段,能响应更多的请求)