Queue在线程间安全暂存消息,配合轮询实现轻量级双向网络通信:服务端用request_queue接收请求、response_queue返回响应;客户端用send_queue发指令、recv_queue收结果;需设超时和休眠避免忙等。

在简单的网络通信练习中,用 Queue 实现客户端与服务端的轮询,核心不是让 Queue 直接收发网络数据,而是用它在线程间安全地暂存待处理的消息,配合“主动轮询”逻辑(比如定时检查队列是否有新消息),来模拟轻量级的双向通信。这种方式适合学习理解线程协作和基础网络模型,不依赖复杂框架或长连接。
服务端:用 Queue 接收请求、缓存响应
服务端启动一个监听线程接收客户端连接和数据,把解析后的请求放入一个 queue.Queue;另起一个工作线程从队列里取请求、处理、生成响应,再把响应存入另一个响应队列(或直接发回)。主循环或专门的发送线程轮询响应队列,有数据就发给对应客户端。
- 创建两个队列:
request_queue = queue.Queue()和response_queue = queue.Queue() - 接收线程:
conn.recv()→ 解包 →request_queue.put((conn, data)) - 处理线程:循环
request_queue.get()→ 处理 →response_queue.put((conn, result)) - 发送线程(轮询):定期检查
response_queue.qsize() > 0,有则conn.send(result)并task_done()
客户端:用 Queue 缓存待发指令、轮询等待结果
客户端不依赖回调或阻塞 recv,而是把要发送的命令先放进本地 send_queue,由一个后台线程轮询该队列并调用 send();同时,另一线程持续调用 recv()(可设短超时如 0.1 秒),收到数据后放入 recv_queue。业务逻辑只跟这两个队列交互,无需直接碰 socket。
- 发起请求:写入
send_queue.put(b"GET_TIME") - 发送线程:while True: if not send_queue.empty(): s.send(send_queue.get())
- 接收线程:while True: try: data = s.recv(1024); recv_queue.put(data) except socket.timeout: pass
- 业务代码轮询:if not recv_queue.empty(): print(recv_queue.get())
关键细节:避免忙等 + 确保线程安全
轮询不能无休止空转,否则吃满 CPU。所有对 Queue 的操作天然线程安全,但轮询间隔和超时设置直接影响响应性和资源占用。
- 用
queue.get_nowait()或queue.empty()配合time.sleep(0.01)控制轮询节奏 - socket 接收务必设
sock.settimeout(0.05),避免 recv 卡死导致轮询中断 - 不要用
while not q.empty(): q.get()—— 应改用try/except queue.Empty或q.get(timeout=0.1) - 多个线程共用同一 socket 有风险,建议每个 socket 由固定线程负责收/发,队列只传数据不传 socket
为什么不用 select/poll?什么时候该升级?
纯 Queue + 轮询适合单客户端、低频交互的教学场景,代码直观易调试。但它无法高效管理多个连接,也不符合真实服务端模型。一旦需要支持多客户端并发、低延迟响应或高吞吐,就应切换到 select、asyncio 或 threading + blocking I/O 分连接处理——此时 Queue 可继续用于线程间任务分发(如把请求丢进处理池),但不再承担 I/O 轮询职责。

















