一、IO模型简介
- 什么是io模型
'''
我们说的io模型都是针对网络io的
Stevens在文章中一共比较了五种IO Model:
* blocking IO 阻塞IO
* nonblocking IO 非阻塞IO
* IO multiplexing IO多路复用
* signal driven IO 信号驱动IO
* asynchronous IO 异步IO
由signal driven IO(信号驱动IO)在实际中并不常用,所以主要介绍其余四种IO Model。
'''

- 等待数据准备(Waiting for the data to be ready)
- 将数据从内核拷贝到进程中(Copying the data from the kernel to the process)
- 对于TCP网络编程
- 同步异步
- 阻塞非阻塞
- 常见的网络阻塞状态
- accept
- recv
- recvfrom
- send: 虽然也有io行为, 但是不在我们的考虑范围
- 理解过程见图


二、阻塞io

- 代码演示
# 客户端.py
import socket
client = socket.socket()
client.connect(('127.0.0.1', 8080))
while True:
client.send(b'hello zpp')
data = client.recv(1024)
print(data.decode('utf-8'))
# 服务端.py
import socket
import time
server = socket.socket()
server.bind(('127.0.0.1', 8080,))
server.listen(5)
while True:
conn, addr = server.accept()
while True:
try:
data = conn.recv(1024)
print(data)
conn.send(data.upper())
except ConnectionError as e:
break
conn.close()
- 在服务端开启多进程或者多线程 进程池线程池并没有解决io问题, 只是各自有各自的io
三、非阻塞io

# 服务端.py
import socket
import time
server = socket.socket()
server.bind(('127.0.0.1', 8080,))
server.listen(5)
# 将所有的阻塞变为非阻塞
server.setblocking(False)
r_list = []
del_list = []
while True:
try:
conn, addr = server.accept()
r_list.append(conn)
except BlockingIOError:
# print('做其他事')
time.sleep(0.1) # 坚决不可以这么写,为了演示计算机不跑死
print('列表的长度:', len(r_list))
for conn in r_list:
try:
data = conn.recv(1024) # 没有消息 报错
if len(data) == 0: # 客户端断开链接
conn.close() # 关闭conn
# 将无用的conn从r_list删除
del_list.append(conn)
continue
conn.send(data.upper())
except BlockingIOError:
continue
except ConnectionError:
conn.close()
del_list.append(conn)
# 回收无用链接
for conn in del_list:
r_list.remove(conn)
del_list.clear()
# 客户端.py
import socket
client = socket.socket()
client.connect(('127.0.0.1', 8080))
while True:
client.send(b'hello zpp')
data = client.recv(1024)
print(data.decode('utf-8'))
- 总结
- 虽然非阻塞io非常牛
- 但是该模型会长时间占用cpu并且不干活, 让cpu不停的空转
- 极度消耗cpu资源
- 实际应用中也不考虑使用非阻塞io
- 任何技术点都有他存在的意义
- 实际应用或者是思想借鉴
四、io多路复用

- 代码演示
import socket
import select
server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)
server.setblocking(False)
read_list = [server]
while True:
r_list, w_list, x_list = select.select(read_list, [], [])
'''
帮你监管
一旦有人来了 立刻给你返回对应的监管对象
'''
# res = select.select(read_list, [], [])
# print(res) # ([<socket.socket fd=472, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080)>], [], [])
# print(server)
for i in r_list:
# 针对不同的对象做不同的处理
if i is server:
conn, addr = i.accept()
# 也应该添加到监管队列中
read_list.append(conn)
else:
res = i.recv(1024)
if len(res) == 0:
i.close()`在这里插入代码片`
# 将无效的监管对象 移除
read_list.remove(i)
continue
print(res)
i.send(b'heiheihiehieh')
- 总结
- 当监管的对象只有一个时, 其实io多路复用连阻塞io都比不上
- 但是io多路复用可以一次监管很多对象
- 监管机制是操作系统本身就有的, 如果想用该监管机制(select), 需要你导入对应的(select)模块
- 总结监管机制
'''
监管机制其实有很多
select机制, windows\linux都有
poll机制 只有linux有 poil和select都可以监管多个对象, 但是poll监管的数量更多
上述select和poll机制其实都不是很完美, 当监管的对象特别多的时候,可能会出现,极大的延时响应
epoll机制 只在linux有
它给每一个监管对象都绑定一个回调机制 ,一旦有响应, 回调机制立即发起提醒
针对不同的操作系统还需要考虑不同的监测机制, 书写代码太多繁琐,有一个能够根据你跑的平台的不同自动帮你选择对应的监管机制的selectors模块
'''
五、异步IO(上面是发展史, 这里是使用, 后面会介绍异步框架)

- 代码演示
在这里插入代码片
相关连接(笔记来自于视频课程的归类整理):
[1]: https://www.bilibili.com/video/BV1QE41147hU?p=17
[2]: https://www.cnblogs.com/Dominic-Ji/p/11093137.html
[3]: https://www.cnblogs.com/xiaoyuanqujing/p/11636160.html
本文深入探讨了网络编程中的五种IO模型,包括阻塞IO、非阻塞IO、IO多路复用和异步IO。通过代码示例解释了各种模型的工作原理及其优缺点。阻塞IO会导致线程等待,非阻塞IO虽避免等待但消耗CPU资源,而IO多路复用如select和epoll能有效监管多个对象。最后,异步IO通过回调机制提供高效解决方案。
4万+

被折叠的 条评论
为什么被折叠?



