网络IO模型
网络IO模型有很多,它们都是为了解决一个问题:减少IO等待时间,提高计算机效率
- 应用程序遇到IO操作,会阻塞在原地等待,这样降低了计算机的执行效率。
- 为了解决这个问题,先后出现了多种IO模型。
# 阻塞IO blocking IO
# 非阻塞IO nonblocking IO
# 多路复用IO IO multiplexing
# 信号驱动IO signal driven IO
# 异步IO asynchronous IO
由signal driven IO(信号驱动IO)在实际中并不常用,所以主要介绍其余四种IO Model。
IO发生时涉及到的两个对象:
- 一个是调用这个IO的任务对象(线程或进程)
- 一个是系统内核(可以简单理解为操作系统)
- IO模型的不同,主要体现在如何处理这以下两个阻塞阶段上
# IO操作时,两个对象之间存在两个行为阶段(两个阻塞阶段):
- 等待数据 wait data (Waiting for the data to be ready)
- 拷贝数据 copy data (Copying the data from the kernel to the process)
产生IO的行为
1、被动等待接受:read、readv、recv、recvfrom、recvmsg、accept
2、主动发送数据:write、writev、send、sendto、sendmsg、connect
# 网络IO主要表现在 accept、recv、recvfrom
# 被动等待数据的时间一般很长,这就是IO操作遇到阻塞的主要原因。
# 不论是收数据还是发送数据,都是直接跟自己的操作系统打交道,问自己的OS要数据或将数据交给OS发出去。
# 因此被动等数据的时间很长,主动发数据就很容易,因此可以不考虑send这种网络IO(忽略不计)。
下面以socket通信为背景介绍网络IO模型
阻塞IO
默认所有IO都是阻塞IO。
-
阻塞IO时:完完全全经历了
wait data
和copy data
两个阻塞阶段,等待时间最长。 -
解决办法:开多线程或多进程,同时处理多个客户端的请求,再设置半连接池和进程池(线程池)。
-
缺点:系统硬件资源有限,不可能无限制的开多进程或多线程。
-
适用:适用在小规模的并发服务请求。
非阻塞IO
可以将socket设置为非阻塞模式,此时accept
和recv
就不会再原地等待了。
server.setblocking(False) # 默认是True, 为阻塞IO
- 非阻塞IO时,在
wait data
阶段,应用程序可以干点别的事情,不会傻傻的原地等待,只是时不时地询问一下数据是否来到(轮询);数据到了后再经历copy data
阻塞阶段获取数据。此时,只经历了copy data
阻塞阶段。 - 解决办法:通过轮询的方式避免
wait copy
阶段的阻塞时间。 - 缺点:<1> 轮询(长时间处于死循环状态)严重消耗硬件资源。<2> 轮询造成响应时间延长了。
- 不推荐使用。
多路复用IO
多路复用IO,是将轮询的任务单独拎出来,交给一个'中介'监管。应用程序只要向这个'中介'询问一次,'中介'就帮你等待,等数据到了再通知你过来取数据。相当于你向中介找房子,中介帮你等房源;等房源到了之后再通知你去看房。
-
监管机制:监管机制(即'中介')是操作系统内部的机制,可以调用select模块实现。
import select r_list = [server] # 将待监管的对象放在一起,交给select帮我们监管起来,后面的conn对象再放进去 readable_list, *_ = select.select(read_list, [], [])
-
解决方法:监管机制,app无需经历
wait data
阻塞阶段,也不一直占用CPU资源('中介'帮忙等数据)。 -
优点:单线程(或进程)实现并发,降低IO等待时间。只经历
copy data
阻塞阶段。 -
缺点:
- <1> 当并发规模过大时,造成响应延迟(遍历可读列表需要耗时增加);
- <2> 监管对象极少时不如阻塞IO的多线程并发。
-
适用:中等规模并发服务请求。
-
强调:应用程序不经历
wait data
阻塞阶段,但整个进程或线程是被select阻塞的。
# 监管机制其实有很多
select机制 windows linux都有
poll机制 只在linux有 poll和select都可以监管多个对象 但是poll监管的数量更多
上述select和poll机制其实都不是很完美 当监管的对象特别多的时候,可能会出现 极其大的延时响应
epoll机制 只在linux有
它给每一个监管对象都绑定一个回调机制
一旦有响应 回调机制立刻发起提醒
针对不同的操作系统还需要考虑不同检测机制 书写代码太多繁琐
有一个人能够根据你跑的平台的不同自动帮你选择对应的监管机制
# selectors模块
异步IO
异步IO通过异步提交任务 + 回调机制的方式降低阻塞等待时间。
- 原理:任务异步替提交后,不做任何等待,直接处理其他任务。相当于,我向中介找房子,中介接到任务后开始等待房源;等房源到了之后他自己主动先去看房,看房结束后,主动告诉我说好了可以去住了。
- 操作系统收到数据后,主动将数据拷贝给app内存,然后通知app说数据好了,app不经历
copy data
阻塞阶段。 - 异步IO,应用程序不经历
wait data
和copy data
两个阻塞阶段。 - 优点:异步IO模型是所有模型中效率最高的,也是使用最广泛的
# 相关的模块和框架
- 模块:asyncio模块
- 异步框架:sanic tronado twisted
总结
- 阻塞IO, 经历两个阻塞阶段,可以用多线程(进程)实现小规模并发
- 非阻塞IO,经历一个阻塞阶段,死循环严重消耗CPU资源,不推荐
- 多路复用IO,经历两个阻塞阶段,通过监管机制,实现单线程内中等规模并发
- 异步IO,不经历阻塞阶段,异步加回调机制,实现大规模高并发
参考博客: