Python 同步原语与队列

锁、事件与队列协调并发任务;优先用队列传递所有权,降低共享内存复杂度。

#type / concept #status / growing #tech / dev #resource / python #tech / lang / python

[!info] 关联笔记

Python 同步原语与队列

这个概念为什么出现

多线程/多协程共享计数器、连接池、缓冲时,需要协调。锁能保临界区;队列常常更简单:把数据所有权在任务间传递,减少共享写。

[!abstract] 一句话理解 同步原语保护共享状态;队列实现生产者-消费者解耦。能队列就别到处加锁。

最小可运行示例

先把示例放进业务场景,再看代码:

场景:异步爬虫:生产者放 URL,消费者写结果

# async_queue_demo.py
# 业务意图:队列传递任务,避免共享 list 乱追加。
# 教学点:
# - asyncio.Queue;
# - worker 消费;
# - join 等待完成。

import asyncio


async def worker(name: str, q: asyncio.Queue[str], out: list[str]) -> None:
    while True:
        url = await q.get()
        try:
            await asyncio.sleep(0.05)
            out.append(f"{name}:{url}")
        finally:
            q.task_done()


async def main() -> None:
    q: asyncio.Queue[str] = asyncio.Queue()
    out: list[str] = []
    workers = [asyncio.create_task(worker(f"w{i}", q, out)) for i in range(2)]
    for u in ["u1", "u2", "u3"]:
        await q.put(u)
    await q.join()
    for w in workers:
        w.cancel()
    print(sorted(out))


if __name__ == "__main__":
    asyncio.run(main())

建议运行:

python async_queue_demo.py

期望输出(worker 分配可能不同,集合应一致):

['w0:u1', 'w0:u3', 'w1:u2']

或等价排列。

结合场景再看三个关注点

  1. Queue 自带协调,减少手写条件变量。
  2. task_done/join 表达“任务排空”。
  3. 线程世界对应 queue.Queue

核心概念与准确模型

原语场景
Lock/Mutex临界区
RLock可重入
Event一次性信号
Semaphore限流
Queue传递工作项

边界情况与反直觉行为

  1. 锁粒度太大吞吐下降。
  2. 未 join 就退出丢任务。
  3. 异步锁与线程锁不能混用错环。

常见误区

[!warning] 常见误区:所有共享都靠全局 list+锁 错误理解:唯一模式。
正确模型:优先所有权转移(队列)与不可变消息。

工程实践

  • 有界队列做背压
  • 超时获取避免永久阻塞
  • 指标:队列深度

本节总结

同步工具保护正确性;队列简化架构。并发代码的可读性往往来自“少共享”。

自测题

  1. 为何队列能减少锁?
  2. task_done 的作用?
参考答案
  1. 数据所有权随消息移动,降低同时写共享结构。
  2. 标记单条任务处理完成,使 join 可等待排空。

延伸阅读与资料来源

资料类型支撑内容
asyncio.Queue文档异步队列
threading文档线程原语
创建于 2026/7/15 更新于 2026/7/15