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

在Python中,为何select.select需要在循环中加入sleep?

问题原因分析及解决方案

你的问题核心在于把同一个socket同时塞进了select的读集合和写集合,再加上无延迟的忙循环,导致读事件被完全抢占。具体拆解:

  • 当你调用select([sock], [sock], [])时,只要socket处于可读或可写状态,select就会立即返回。而socket的写缓冲区大部分时间都是空闲的(send操作很快就能完成,缓冲区不会被填满),所以没有sleep的情况下,select几乎瞬间就会返回,且wlist永远包含当前socket。
  • 程序进入疯狂的忙循环,反复执行send操作,占用了99%以上的CPU时间。哪怕此时有数据到达socket的接收缓冲区,select虽然会同时返回rlist和wlist,但程序在极短时间内又会重新调用select,导致recv的执行机会被挤压到可以忽略的程度,看起来就像“无法接收数据”。
  • 加上time.sleep(0.1)后,程序每次循环都会让出CPU,给操作系统足够的时间去处理socket的读事件,把网络数据写入接收缓冲区,这样select才能正确检测到读就绪,让recv有机会执行。

修复方案

你应该只在需要发送数据的时候,才把socket加入写集合,而不是每次循环都强制监听写事件:

# 先定义一个标记,记录是否有数据待发送
need_send = False

while True:
    # 初始只监听读事件,写事件按需添加
    listen_read = [sock]
    listen_write = [sock] if need_send else []
    
    rlist, wlist, _ = select.select(listen_read, listen_write, [])

    for rsock in rlist:
        new_data = rsock.recv(RCV_SIZE)
        # 示例:假设收到数据后需要回复,标记待发送状态
        if new_data:
            need_send = True

    for wsock in wlist:
        wsock.send(other_data + TERMINATOR)
        need_send = False  # 发送完成后取消写事件监听

这种写法不需要sleep也能稳定处理读写事件,避免了忙循环抢占CPU的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 16:10:03