系列文章目录
文章目录
- 系列文章目录
- 一、I/O模型的介绍
- 二、阻塞I/O模型
- 三、非阻塞I/O
- 四、I/O多路复用模型
- 五、异步I/O模型
一、I/O模型的介绍
本文中的I/O模型仅考虑网络I/O,其他I/O不在考虑范围内。
- 预备知识点:
内存分为内核缓冲区和用户缓冲区。网络下载的资源,硬盘加载的资源,先放到内核缓冲区,之后再拷贝到应用程序的缓冲区,应用程序才能用这个数据。 - 五种I/O模型:
- blocking I/O —— 阻塞I/O
- nonblocking I/O —— 非阻塞I/O
- I/O multiplexing —— I/O多路复用
- signal driven I/O —— 信号驱动I/O (不常用)
- asynchronous I/O —— 异步I/O(其他四个也被称为同步I/O)
I/O模型只是一种编程的“套路”,合理的使用,可以提高程序的效率,减少阻塞。
二、阻塞I/O模型
这是最简单的I/O模型,应用程序执行系统调用后,就一直在阻塞,直到收到数据。
三、非阻塞I/O
该模型中,用程序发起系统调用,操作系统立刻进行回复,所以应用程序不会阻塞,可以进行其他任务,或继续进行系统调用,查询是否有要接收的数据。
此模型并不阻塞,但是需要循环查询,浪费CPU,低效。
- 代码实现:
在socket中,设置套接字对象.setblocking(False)
可以变为非阻塞模型。
"""
服务端
"""
import socket
import time
server = socket.socket()
server.bind(('127.0.0.1', 8082))
server.listen(5)
server.setblocking(False) # 将所有的网络阻塞变为非阻塞
# 保存连接
r_list = []
# 保存被删除连接
del_list = []
while True:
try:
conn, addr = server.accept()
r_list.append(conn)
except BlockingIOError: # 代表没有连接请求,可以去做其他的事
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 ConnectionResetError:
conn.close()
del_list.append(conn)
# 断开无用的链接
for conn in del_list:
r_list.remove(conn)
del_list.clear()
"""
客户端
"""
import socket
client = socket.socket()
client.connect(('127.0.0.1',8081))
while True:
client.send(b'hello world')
data = client.recv(1024)
print(data)
四、I/O多路复用模型
操作系统提供了多种监管机制,能够帮助我们监管socket对象和connect对象,并且能监管很多个,只要有事件触发,就会立刻给我们返回一个“可用”的信号。收到信号后,就可以调用recv()
、accept()
等方法了。
select机制windows linux都有;poll机制只在linux有;poll和select都可以监管多个对象,但是poll监管的数量更多。如果需要跨平台就使用selectors模块,该模块会自动识别平台,使用对应的监管机制。
I/O多路复用模型不适用于单个连接。
- 代码实现:
python内置select(与机制同名)模块,能帮助我们使用select机制:
"""
服务端
"""
import socket
import select
server = socket.socket()
server.bind(('127.0.0.1',8082))
server.listen(5)
server.setblocking(False) # 改为非阻塞
# 要监管对象的列表
read_list = [server]
while True:
# r_list是套接字对象,其他两个用不到,返回值为空
r_list, w_list, x_list = select.select(read_list, [], [])
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'hello python')
"""
客户端
"""
import socket
client = socket.socket()
client.connect(('127.0.0.1',8081))
while True:
client.send(b'hello world')
data = client.recv(1024)
print(data)
五、异步I/O模型
异步IO模型是所有模型中效率最高的,也是使用最广泛的!
应用程序发起系统调用后,会得到立刻一个恢复,然后应用程序就可以去执行其他任务。而操作系统接收到数据后,会立刻给应用程序发送一个信号,表示之前的系统调用有结果了。
- 代码实现:
实现异步I/O模型需要借助于asyncio模块。
import threading
import asyncio
@asyncio.coroutine
def hello():
print('hello world %s'%threading.current_thread())
yield from asyncio.sleep(1) # 换成真正的IO操作
print('hello world %s' % threading.current_thread())
loop = asyncio.get_event_loop()
tasks = [hello(),hello()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()