在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
相关产品推荐
相关产品推荐

