一、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()
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, 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)
print('hello world %s' % threading.current_thread())
loop = asyncio.get_event_loop()
tasks = [hello(),hello()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
|