什么是IO模型?
IO指的是输入输出,其执行速度非常慢
模型,只固定的套路
IO模型就是指实现输入输出的套路
1.本地IO 指的是输入输出到本地计算机 如:写入硬盘
2.网络IO 指的是输入输出到网络中的计算机,速度远比本地IO慢
网络IO输入输出过程
IO模型的分类(重点)
1.阻塞型IO
之前学习的IO操作除了gevent都是阻塞型的
1.可以利用多线程来提高IO
线程不能太多,会造成内存溢出
2.线程池可以解决下线程太多问题
但如果线程池达到最大数,其他客户端将进入等待
3.在单线程下并发来处理 可以使单核下的效率最高
2.非阻塞IO
非阻塞IO的服务器
import socket server = socket.socket() server.bind(('192.168.1.67',4396)) server.listen() #设置为非阻塞IO server.setblocking(False) #存放所有连接过来的客户端 clients = [] while True: try: client,addr = server.accept() print('连入了一个客户端!') clients.append(client) except BlockingIOError: #已经关闭的客户端 close_c = [] #将要回复的客户端以及数据 msg_ls = [] #接受数据循环 for c in clients: try: data = c.recv(1024) if not data: c.close() close_c.append(c) #不能直接发,因为操作系统缓存满了会抛出异常 msg_ls.append((c,data)) except BlockingIOError: pass except ConnectionResetError: c.close() close_c.append(c) #发送数据的循环 #保存已发送的客户端和数据 rm_msg = [] for client_and_data in msg_ls: client = client_and_data[0] data = client_and_data[1] try: client.send(data.upper()) #加入删除列表 rm_msg.append(client_and_data) except BlockingIOError: pass #从将要回复的客户端和数据列表删除已经发送的成功客户端和数据 for i in rm_msg: msg_ls.remove(i) #清空已经发送完成的客户端和数据列表 rm_msg.clear() #从连入的客户端列表删除已经关闭的客户端列表 for c in close_c: clients.remove(c) #清空已经关闭的客户端列表 close_c.clear()
非阻塞IO客户端
import socket import os,time client = socket.socket() client.connect(('192.168.1.67',4396)) while True: msg = 'hello i am:%s'%os.getpid() time.sleep(1) if not msg: continue client.send(msg.encode('utf-8')) data = client.recv(1024) print(data.decode('utf-8'))
3.多路复用
什么是多路复用?
多个连接复用一个线程 反过来说就是一个线程处理多个连接 提高了单线程的处理能力
多路复用提高的是单线程处理网络IO的效率
协程提升的是单线程处理所有IO的效率
多路复用服务器:
import socket,select server = socket.socket() server.bind(('192.168.1.67',4396)) server.listen() #select 是帮我们监控连接 #需要给他传两个参数列表,一个检测是否可读(是否可以执行recv),一个检测是否可写(是否执行send) rlist = [server,] wlist = [] #默认select是阻塞的.直到其中有一个或几个需要被处理 #存储要发送的数据 msg = {} #返回值: #1.可读的连接(可以执行recv) #2.可写的连接(可以执行send) while True: readable_list,writeable_list,_ = select.select(rlist,wlist,[]) #接下来处理可读可写的列表 #处理可读的列表 for c in readable_list: if c == server:#说明当要被处理的是服务器 client,addr = server.accept() #把客户端交给select来检测是否可读 rlist.append(client) else: print('客户端可以recv了!') data = c.recv(1024) print(data.decode('utf-8')) #将客户端也交给select来检测是否可写 wlist.append(c) msg[c] = data #处理可写列表 for w in writeable_list: w.send(msg[w].upper()) #将已经发送完成的连接从检测列表删除 wlist.remove(w)
多路复用客户端:
import socket,os,time client = socket.socket() client.connect(('192.168.1.67',4396)) while True: msg = 'hello i am:%s'%os.getpid() time.sleep(1) if not msg: continue client.send(msg.encode('utf-8')) print(client.recv(1024).decode('utf-8'))
4.异步IO