浅谈Python基础之I/O模型
什么是I/O模型
I/O模型是指在计算机系统中,处理器对外设进行输入输出数据的方式或模式。常见的I/O模型有以下几种:
- 同步阻塞IO(Blocking I/O)
- 同步非阻塞IO(Non-Blocking I/O)
- I/O多路复用(I/O Multiplexing)
- 异步IO(Asynchronous I/O)
在Python中,以上I/O模型都有所应用,其中I/O多路复用是最为常用的。
Python的I/O多路复用
在Python中,I/O多路复用的实现方式主要使用select/poll/epoll模块。这三者都提供了一种通用的方式,使得一个线程能够同时处理多个I/O操作。我们可以通过这些模块实现多个socket的异步通信,从而提高系统的IO吞吐量。
以下是基于select模块的socket实现示例:
import select
import socket
# 创建socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(('localhost', 8000))
server_socket.listen(5)
# 创建select实例
inputs = [server_socket]
outputs = []
# 进入循环
while True:
readable, writable, exceptional = select.select(inputs, outputs, inputs)
for s in readable:
# 判断是否有新的连接
if s is server_socket:
client_socket, address = server_socket.accept()
print('接受来自客户端 %s 的连接' % str(address))
inputs.append(client_socket)
# 接收客户端的数据
else:
data = s.recv(1024)
if data:
print('接受来自客户端的数据:%s' % data.decode('utf-8'))
if s not in outputs:
outputs.append(s)
# 客户端关闭连接
else:
print('客户端 %s 关闭连接' % str(s.getpeername()))
if s in outputs:
outputs.remove(s)
inputs.remove(s)
s.close()
for s in writable:
# 将数据发送给客户端
s.send(b'Hello, world!')
outputs.remove(s)
for s in exceptional:
# 处理异常
inputs.remove(s)
if s in outputs:
outputs.remove(s)
s.close()
在上面的示例中,我们创建了一个socket实例并绑定到本地地址和端口。然后创建一个select实例,并将输入的socket添加到input列表中,当有数据可读、数据可写或者出现异常时,select实例会返回对应的socket,并通过相应操作进行处理。
I/O多路复用的优缺点
使用I/O多路复用的优点在于可以将多个socket的读写事件监听在同一个线程上,从而提高系统的效率。同时,因为没有多线程/多进程的切换开销,所以对系统资源的消耗相对较小。另外,I/O多路复用适用于连接数较少、连接时间较长或者交互数据量较小的场景。
但在使用I/O多路复用的过程中,也会有一些缺点。因为一个线程只能负责一个socket的读写,当存在大量socket时,会阻塞主线程,并且在处理文件描述符的过程中,需要将数据复制从内核空间复制到用户空间,可能会导致数据的重复复制,进一步影响效率。
总结
Python的I/O模型有多种,其中最为常用的是I/O多路复用。在实现I/O多路复用时,我们可以使用select/poll/epoll模块。这样可以提高系统效率,但也需要注意I/O多路复用的优缺点。
示例说明
以上代码示例中,我们创建了一个socket服务器,使用了select模块进行IO多路复用,接收到客户端发送的消息后将其打印并回复一个“Hello World!”的消息。界面可使用telnet模拟客户端连接服务器,并发送消息进行测试。
以下代码示例是基于异步IO模型的实现方式。
import asyncio
async def tcp_echo_client(reader, writer):
while True:
data = await reader.read(1024)
message = data.decode()
print(f"接受到消息: {message}")
writer.write(data)
await writer.drain()
writer.close()
async def tcp_echo_server():
server = await asyncio.start_server(tcp_echo_client, '127.0.0.1', 8888)
async with server:
await server.serve_forever()
asyncio.run(tcp_echo_server())
以上代码示例中,我们使用了Python 3.7中引入的asyncio模块,创建了一个异步的TCP服务器,在接收到客户端的消息后,将其打印并返回给客户端。我们可以使用telnet模拟客户端连接并发送消息进行测试。当我们需要创建高效、高并发的网络程序时,异步IO模型是一个不错的选择。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅谈Python基础之I/O模型 - Python技术站