You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求通俗讲解Python的select、selectors模块在socket开发中的作用

通俗理解Python的select、selectors库(socket服务端场景)

首先我们先从你写原生socket服务端的常见痛点讲起:

  • 你写最基础的TCP服务端时,通常会循环调用accept()等待客户端连接,连接建立后再调用recv()等待客户端发数据对吧?
  • 这时候就会碰到阻塞IO的问题:如果没有客户端连接,程序会直接卡死在accept();有一个客户端连上但没发数据,程序又卡死在recv(),其余客户端完全没法接入,同一时间只能处理一个连接。

1. select库的核心作用

你可以把select理解成一个「socket状态巡检员」:你提前把所有需要监控的socket(用来监听新连接的服务端socket、已经建立连接的客户端socket)都交给它,它会帮你盯着这些socket的状态变化,直到至少有一个socket满足你要的条件(比如有新连接进来、有客户端发数据了)才会返回,你再挨个处理这些就绪的socket即可。

  • 这就是最基础的IO多路复用实现,不用再死等某一个socket,同一时间可以处理上百个连接。
  • Python的select.select()方法有三个核心入参,分别是三类你要监控的socket列表:「等待读就绪的socket列表」、「等待写就绪的socket列表」、「等待异常的socket列表」,返回值就是三类中已经就绪的socket列表,直接遍历处理即可。
  • 它的缺点也很明显:每次调用都要传入全量的待监控socket列表,内部要遍历所有socket检查状态,连接数越高效率越低,而且默认最多只能监控1024个socket。

2. selectors库的核心作用

selectors是Python对底层多路复用机制的高层封装,它会自动根据你当前的操作系统选择最优的多路复用实现:Linux下用epoll、BSD/macOS下用kqueue、Windows下默认用select,不需要你自己做平台适配。

  • 用法比原生select简单很多:你只要创建一个selectors.DefaultSelector()实例,调用register()方法把待监控的socket、要监控的事件(读/写)、对应的回调函数传进去即可,之后循环调用select()就能拿到所有就绪的事件,直接执行对应回调就行。
  • 性能远优于原生select,没有1024个连接的上限,也不用每次都传入全量的socket列表。

极简使用示例对比

原生select实现简易服务端

import select
import socket

server_sock = socket.socket()
server_sock.bind(('0.0.0.0', 8080))
server_sock.listen(100)
# 初始化待监控的读就绪socket列表,初始只有服务端监听socket
read_list = [server_sock]

while True:
    # 阻塞到至少有一个socket就绪
    readable, _, _ = select.select(read_list, [], [])
    for sock in readable:
        if sock is server_sock:
            # 有新连接接入,加入监控列表
            conn, addr = sock.accept()
            read_list.append(conn)
        else:
            # 客户端发来了数据
            data = sock.recv(1024)
            if not data:
                sock.close()
                read_list.remove(sock)
            else:
                print(f"收到数据:{data.decode()}")

selectors实现简易服务端

import selectors
import socket

sel = selectors.DefaultSelector()
server_sock = socket.socket()
server_sock.bind(('0.0.0.0', 8080))
server_sock.listen(100)

def accept_conn(sock):
    conn, addr = sock.accept()
    # 注册新连接的读事件,绑定接收数据的回调
    sel.register(conn, selectors.EVENT_READ, handle_recv)

def handle_recv(conn):
    data = conn.recv(1024)
    if not data:
        sel.unregister(conn)
        conn.close()
    else:
        print(f"收到数据:{data.decode()}")

# 先注册服务端监听socket的读事件,绑定接入连接的回调
sel.register(server_sock, selectors.EVENT_READ, accept_conn)

while True:
    # 阻塞获取所有就绪事件
    events = sel.select()
    for key, mask in events:
        # 直接执行对应回调
        callback = key.data
        callback(key.fileobj)

内容的提问来源于stack exchange,提问作者Lionheart2007

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.16 20:45:07