queue本身不轮询,而是作为线程安全缓冲区,配合while循环+get_nowait()或empty()实现轻量轮询;目的是避免阻塞、保持主线程响应性并控制检查频率。

在简单的网络通信练习中,用 Queue 实现轮询,核心不是让 Queue 主动“轮询”,而是用它作为线程安全的缓冲区,配合一个持续检查队列是否非空的循环(即手动轮询),来协调收发逻辑。关键在于:Queue 本身不轮询,你用 while 循环 + queue.get_nowait() 或 queue.empty() 来模拟轻量轮询行为。
为什么不用阻塞式 get,而要轮询?
在练习场景(比如模拟客户端反复发请求、服务端逐个响应),你往往希望:
- 主线程不被卡住,能同时做其他事(如打印状态、接收用户输入);
- 避免因没有消息时无限等待,导致程序假死;
- 控制检查频率(比如每 100ms 看一次有没有新数据)。
用 queue.empty() + get_nowait() 做安全轮询
这是最常用、最稳妥的方式。注意不能只靠 empty() 判断后直接 get(),因为中间可能被其他线程取走,造成 Empty 异常。
正确写法示例(服务端接收消息):
import queue
import time
<p>msg_queue = queue.Queue()</p><h1>模拟另一个线程往里放数据(比如 socket 收到包后 put)</h1><p>def mock_receiver():
time.sleep(0.5)
msg_queue.put("Hello from client")
time.sleep(0.3)
msg_queue.put("ACK received")</p><h1>启动接收模拟(可放在 threading.Thread 中)</h1><p>import threading
threading.Thread(target=mock_receiver, daemon=True).start()</p><h1>主循环:轮询队列</h1><p>while True:
try:
msg = msg_queue.get_nowait() # 非阻塞取
print(f"处理消息:{msg}")
except queue.Empty:
pass # 没消息,继续下一轮
time.sleep(0.1) # 控制轮询间隔,避免空转太猛
</p>结合 socket 的简易轮询结构
真实练习中,通常一边用 socket.recv 接收数据并放入 Queue,另一边用轮询从 Queue 取出处理:
- 单独开一个接收线程:循环调用
sock.recv(),成功则q.put(data); - 主线程或处理线程:用上面的
get_nowait()轮询方式消费; - 不必给 Queue 设 maxsize,练习中默认无上限即可;
- 若需区分消息类型(如 request/response),可在 put 时用 tuple 封装,例如
q.put(("REQ", data))。
小提醒:轮询不是万能,别滥用
纯轮询适合教学和低频练习。实际项目中更推荐:
- 用
queue.get(timeout=0.1)替代get_nowait()+ sleep,语义更清晰; - 对多个 socket,考虑
select或asyncio,比轮询高效得多; - 如果只是想“有消息就立刻处理”,且不介意阻塞,
get()最简单——轮询是为灵活让步。











