Python 的 select
模块提供了一种监控文件描述符(文件、套接字等)状态变化的机制,广泛用于实现非阻塞 I/O 操作。它主要用于网络编程中,用于检测哪些文件描述符已准备好执行 I/O 操作,例如可读、可写或发生异常。
核心功能
select
模块的主要功能是提供一个高效的方法等待多个文件描述符的状态变化。它支持以下三个操作:
- 可读:监控哪些文件描述符有数据可以读取。
- 可写:监控哪些文件描述符可以写入数据而不阻塞。
- 异常:监控哪些文件描述符发生了错误或其他异常事件。
常用函数
select.select(rlist, wlist, xlist[, timeout])
- 参数:
rlist
:需要监控可读状态的文件描述符列表。wlist
:需要监控可写状态的文件描述符列表。xlist
:需要监控异常状态的文件描述符列表。timeout
(可选):超时时间,单位为秒。若为None
,表示无限等待。
- 返回值:包含三个列表,分别表示可读、可写和异常的文件描述符。
- 示例:
- 参数:
import select
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 8080))
sock.listen(5)
sock.setblocking(False)
inputs = [sock]
while True:
readable, writable, exceptional = select.select(inputs, [], [])
for s in readable:
if s is sock: # 新连接
conn, addr = sock.accept()
inputs.append(conn)
else: # 数据读取
data = s.recv(1024)
if data:
print(f'Received: {data.decode()}')
else:
inputs.remove(s)
s.close()
select.poll()
- 提供更灵活的事件监控,可以注册文件描述符及其感兴趣的事件。
- 优于
select.select()
,尤其是在需要监控大量文件描述符时。 - 示例:
import select
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 8080))
sock.listen(5)
sock.setblocking(False)
poller = select.poll()
poller.register(sock, select.POLLIN)
while True:
events = poller.poll()
for fd, flag in events:
if fd == sock.fileno():
conn, addr = sock.accept()
print(f"Connection from {addr}")
poller.register(conn, select.POLLIN)
else:
data = sock.recv(1024)
if data:
print(f"Data received: {data.decode()}")
else:
poller.unregister(fd)
sock.close()
注意事项
- 文件描述符限制:
select.select()
在监控大量文件描述符时会受到操作系统限制(通常 1024 个)。 - 效率问题:
select.select()
会遍历所有监控的文件描述符,因此在大规模应用场景中效率较低。使用epoll
或poll
可以解决这一问题。 - 平台差异:
- Windows:仅支持
select.select()
。 - 类 Unix 系统:支持
select.select()
、select.poll()
,以及epoll
(Linux)和kqueue
(BSD)。
- Windows:仅支持
select
模块是 Python 网络编程的基础组件之一,适合用于构建高性能的异步网络服务器和客户端。