I/O模型
协程是单线程下的并发,并不是对性能都有所提升,一定是检测单个线程下的多个任务的I/O,遇到I/O不要让它阻塞,给它自动切换到其他任务去;这样就能提高单个线程下的运行效率。用gevent模块来实现了,gevent是怎么检测I/O行为的呢,遇到I/O自动切换到其他任务去。
同步异步,同步调用是提交完任务在原地等着结果拿到结果后再运行下行代码;异步调用是提交完就不管了接着往下执行,异步通常跟回调机制连用,我提交完一个任务,这个任务运行完后会自动触发回调函数运行把结果交给它。
同步不定于阻塞。
阻塞I/O
#阻塞I/O 没有并发、遇到阻塞就等着 from socket import * from threading import Thread #可利用多线程实现并发 def communicate(conn): while True: try: data = conn.recv(1024) #等待 if not data: break conn.send(data.upper()) except ConnectionResetError: break conn.close() server = socket(AF_INET, SOCK_STREAM) server.bind(('127.0.0.1',8080)) server.listen(5) while True: print('starting...') conn, addr = server.accept() #wait阶段主要卡在这里 print(addr) t=Thread(target=communicate,args=(conn,)) #让主线程干accept的活,每来一个链接发起个线程让它干通信的活;没有解决I/O阻塞,各个运行互不影响 t.start() #线程池保证机器在健康的状态下运行 server.close()
from socket import * client=socket(AF_INET,SOCK_STREAM) client.connect(('127.0.0.1',8080)) while True: msg=input('>>: ').strip() if not msg:continue client.send(msg.encode('utf-8')) data=client.recv(1024) print(data.decode('utf-8')) client.close()
非阻塞I/O
监测单线程下的I/O,帮你自动切换到另外一个任务
wait和copy阶段是怎么处理的呢
跟gevent一样。
from socket import * server = socket(AF_INET, SOCK_STREAM) server.bind(('127.0.0.1',8083)) server.listen(5) server.setblocking(False) #True是阻塞,False是非阻塞 print('starting...') rlist=[] wlist=[] #send在数据量大的情况下也会阻塞 while True: try: conn, addr = server.accept() #问操作系统有没有数据 ;服务端可以不停的建链接 rlist.append(conn) print(rlist) except BlockingIOError: #捕捉这个异常 #print('干其他的活') #没有数据来就可以干其他的活了, #收消息 del_rlist = [] for conn in rlist: try: data=conn.recv(1024) if not data: del_rlist.append(conn) continue wlist.append((conn,data.upper())) #存放套接字以及准备发的数据 except BlockingIOError: continue except Exception: conn.close() del_rlist.append(conn) #发消息 del_wlist=[] for item in wlist: try: conn=item[0] data=item[1] conn.send(data) del_wlist.append(item) except BlockingIOError: # pass for item in del_wlist:#发成功了把你删了 wlist.remove(item) for conn in del_rlist: #把没有数据发来的conn给删除掉 rlist.remove(conn) server.close()
from socket import * client=socket(AF_INET,SOCK_STREAM) client.connect(('127.0.0.1',8083)) while True: msg=input('>>: ').strip() if not msg:continue client.send(msg.encode('utf-8')) data=client.recv(1024) print(data.decode('utf-8')) client.close()
多路复用I/O模型
from socket import * import select server = socket(AF_INET, SOCK_STREAM) server.bind(('127.0.0.1',8083)) server.listen(5) server.setblocking(False) print('starting...') rlist=[server,] #专门存收消息的 wlist=[] #存发的数据 wdata={} while True: rl,wl,xl=select.select(rlist,wlist,[],0.5) #问操作系统;[]表示出异常的 print('rl',rl) #rlist会不断存conn和server一堆;wlist存一堆conn,缓冲区一旦没满证明就可以发了 print('wl',wl) #wl是可以往缓冲区send值的这种套接字 for sock in rl: if sock == server: #干链接的活 conn,addr=sock.accept() rlist.append(conn) else: try: data=sock.recv(1024) if not data: #针对linux系统 sock.close() rlist.remove(sock) #这个套接字不要监测了 continue wlist.append(sock) wdata[sock]=data.upper() except Exception: sock.close() rlist.remove(sock) ## for sock in wl: data=wdata[sock] sock.send(data) wlist.remove(sock) wdata.pop(sock) server.close()
from socket import * client=socket(AF_INET,SOCK_STREAM) client.connect(('127.0.0.1',8083)) while True: msg=input('>>: ').strip() if not msg:continue client.send(msg.encode('utf-8')) data=client.recv(1024) print(data.decode('utf-8')) client.close()