Python:selectors 库高级用法举例和应用详解

Python:selectors库高级用法举例和应用详解

模块介绍

selectors 库是 Python 3 标准库的一部分,用于实现 I/O 多路复用。它提供了一组跨平台的接口,用于监视多个文件对象,等待它们变为可读、可写或有错误出现。该库是基于更底层的 select 模块,但提供了更高层次和抽象的接口,方便开发者使用。

该模块适配的 Python 版本是 Python 3.4 及以上版本。

应用场景

selectors 库主要用于网络编程和并发编程中的 I/O 操作。当需要在多个网络连接上高效地进行读写操作时,selectors 库能够显著提高性能和资源利用率。它适用于以下场景:

  1. 网络服务器:管理多个客户端连接,同时处理多个 I/O 操作。
  2. Web 抓取:同一时间抓取多个网页,提高抓取速度。
  3. 并发编程:高效管理并处理大量 I/O 任务,避免阻塞。

安装说明

selectors 库是 Python 3 的内置标准库,不需要额外安装。只需确保使用的 Python 版本为 3.4 或更高版本便可直接导入使用。

用法举例

示例 1:简单的 I/O 多路复用

这个例子展示了如何使用 selectors 库监视多个文件对象,确保它们变为可读时进行读取操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import selectors  # 导入selectors库
import socket # 导入socket库

sel = selectors.DefaultSelector() # 创建默认选择器

def accept(sock, mask): # 定义新的客户端连接到来时的回调函数
conn, addr = sock.accept() # 接受新连接
conn.setblocking(False) # 设置为非阻塞
sel.register(conn, selectors.EVENT_READ, read) # 注册新的客户端连接,监听输入事件

def read(conn, mask): # 定义读取数据的回调函数
data = conn.recv(1024) # 从客户端连接读取数据
if data: # 如果有数据
print(f"received {data}") # 打印接收到的数据
else: # 如果连接关闭
sel.unregister(conn) # 注销选择器
conn.close() # 关闭连接

sock = socket.socket() # 新建一个socket对象
sock.bind(('localhost', 12345)) # 绑定到本地地址和端口
sock.listen() # 监听连接
sock.setblocking(False) # 设置为非阻塞
sel.register(sock, selectors.EVENT_READ, accept) # 注册socket,监听输入事件

while True: # 无限循环,等待事件
events = sel.select() # 获取已准备好进行读写的文件对象
for key, mask in events: # 遍历这些事件
callback = key.data # 获取回调函数
callback(key.fileobj, mask) # 执行回调函数

示例 2:客户端连接管理

这个例子展示了如何利用 selectors 库管理多个客户端连接,并对其进行广播消息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import selectors  # 导入selectors库
import socket # 导入socket库

sel = selectors.DefaultSelector() # 创建默认选择器

clients = [] # 保存客户端连接的列表

def accept(sock, mask): # 定义新的客户端连接到来时的回调函数
conn, addr = sock.accept() # 接受新连接
print(f'Accepted connection from {addr}') # 打印客户端地址
conn.setblocking(False) # 设置为非阻塞
sel.register(conn, selectors.EVENT_READ, read) # 注册新的客户端连接,监听输入事件
clients.append(conn) # 添加到客户端列表

def read(conn, mask): # 定义读取数据的回调函数
data = conn.recv(1024) # 从客户端连接读取数据
if data: # 如果有数据
broadcast(data) # 广播数据给所有连接的客户端
else: # 如果连接关闭
print(f'Connection closed by {conn.getpeername()}') # 打印连接关闭信息
sel.unregister(conn) # 注销选择器
clients.remove(conn) # 从客户端列表中移除
conn.close() # 关闭连接

def broadcast(data): # 定义广播数据的函数
for client in clients: # 遍历所有客户端
client.send(data) # 发送数据

sock = socket.socket() # 新建一个socket对象
sock.bind(('localhost', 12345)) # 绑定到本地地址和端口
sock.listen() # 监听连接
sock.setblocking(False) # 设置为非阻塞
sel.register(sock, selectors.EVENT_READ, accept) # 注册socket,监听输入事件

while True: # 无限循环,等待事件
events = sel.select() # 获取已准备好进行读写的文件对象
for key, mask in events: # 遍历这些事件
callback = key.data # 获取回调函数
callback(key.fileobj, mask) # 执行回调函数

示例 3:高效文件读取

本例展示如何利用 selectors 库实现高效文件读取,避免长时间等待文件读取完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import selectors  # 导入selectors库
import os # 导入os库

sel = selectors.DefaultSelector() # 创建默认选择器

def read_file(file, mask): # 定义读取文件的回调函数
data = file.read(1024) # 读取文件数据
if data: # 如果有数据
print(f'Read {len(data)} bytes from file') # 打印读取到的数据字节数
sel.modify(file, selectors.EVENT_READ, read_file) # 重新注册选择器,继续读取
else: # 如果文件读取完毕
print('File read completed') # 打印读取完成信息
sel.unregister(file) # 注销选择器
file.close() # 关闭文件

file = open('example.txt', 'rb') # 打开一个文件
sel.register(file, selectors.EVENT_READ, read_file) # 注册文件对象,监听读事件

while True: # 无限循环,等待事件
events = sel.select() # 获取已准备好进行读写的文件对象
for key, mask in events: # 遍历这些事件
callback = key.data # 获取回调函数
callback(key.fileobj, mask) # 执行回调函数

我强烈建议大家关注我的博客 “全糖冲击博客”。在这里,您将找到所有 Python 标准库的使用教程,不论是网络编程、数据处理还是系统操作,都能查到详尽的讲解和实用的示例代码。通过订阅我的博客,您可以第一时间获取最新技术干货和实战经验,帮助您快速提升 Python 技能。欢迎一键关注,开启更高效的编程之旅!

软件版本可能变动

如果本文档不再适用或有误,请留言或联系我进行更新。让我们一起营造良好的学习氛围。感谢您的支持! - Travis Tang