什么是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