欢迎光临
我们一直在努力

《流畅的Python》读书笔记20: 第四部分 控制流 - Python 并发模型

作者: andylin02
学习章节: 第 19 章 Python 并发模型
关键词: 并发|并行|多线程|多进程|asyncio|GIL|concurrent.futures|事件循环|I/O密集型|CPU密集型


一、本章概述

第 19 章“Python 并发模型”是《流畅的 Python》第 2 版新增的章节,也是整个并发模块的“顶层设计篇”。如果说第 17 章(一期物和并发)介绍的是 concurrent.futures 这个高级并发 API,第 18 章(使用 asyncio 包处理并发)介绍的是异步 I/O 驱动的事件循环模型,那么第 19 章则用更宏观的视角,将 Python 中所有并发方案拼图完整呈现出来。

并发是同时处理多件事,并行是同时做多件事。二者不同,但有联系。
——Rob Pike,Go 语言联合创始人

这一章回答了并发编程的三个根本问题:

  • 什么时候该用哪个并发模型?
  • 不同的模型在底层到底发生了什么?
  • 如何组成一个在实际应用中可扩展的并发系统?
  • 二、本章新增内容

    第 19 章是第 2 版新增的章节,原创内容占比超过 70% :

    板块内容说明
    本节“本章新增内容” 介绍哪些内容来自旧版并发章节的重写、哪些是首发
    第 19.2 节“全景概览” 6 张图示展示了 Python 并发模型的全貌
    第 19.3 节“术语定义” 厘清并发、并行、线程、进程等术语的精准含义
    第 19.4 节“HelloWorld”示例 用旋转指针 spinner 示例同时对比 threading、multiprocessing 和 asyncio 三种并发实现
    第 19.5 节“四种通用并发方案” 逐一实现前文 spinner 示例的四种方案
    第 19.6 节“多核世界的 Python” 以纯文字和图示介绍第三方并发扩展和架构,零代码示例,只提供概要信息和推荐链接
    第 19.7 节“结语” 并发编程核心问题的总结与综述

    三、术语定义:并发 vs 并行

    3.1 核心词汇表

    术语定义
    并发(Concurrency) 程序的结构特征——同时“处理”多件事的方案蓝图
    并行(Parallelism) 程序的执行特征——同时“做”多件事的实际运行
    线程(Thread) 单个进程中的“轻量化”执行单元,共享进程内存
    进程(Process) 操作系统级别的“重型”执行单元,拥有独立内存地址空间
    GIL CPython 解释器的全局解释器锁,确保同一时刻只有一个线程执行 Python 字节码
    协程(Coroutine) 用户级“微线程”,由 Python 运行时调度,可在单线程中提供并发

    3.2 并发与并行的关系

    在 Go 语言联合创始人 Rob Pike 给出的定义基础上,书中还继续说明了这两者之间的逻辑关系:并行是并发的一种特殊案例 —— 所有并行的系统一定会是并发的,但反过来并不成立。

    • 2000 年代初:单核 CPU 的机器可同时处理 100+ 个进程(并发)。
    • 现代 CPU(4 核):系统里同时运行 200+ 个进程,但 CPU 同一时刻能干的活不能超过 4 件事(并行度只能到 4)。

    3.3 并发与并行的影响因素

    任务类型关键指标是否可以并行是否受 GIL 影响
    I/O 密集型(如网络请求、文件读写) 等待 I/O 的时间占比 线程可以有并发效果、asyncio 可提供更高程度的并发 线程数多会影响 GIL 竞争
    CPU 密集型(如数值计算、数据加密) CPU 计算的时间太长 用多进程真正并行,多线程不能提供 CPU 并行的加速 严重影响

    四、一个演示并发的“Hello World”示例

    本书采用经典的“旋转指针(spinner)”类并发示例,分别在 threading、multiprocessing、asyncio 这三个场景下实现相同的任务。我们可以沿用书中 spinner_thread、spinner_proc 和 spinner_async 文件,观察它们在逻辑上的趋同和性能上的差异。

    # spinner_thread.py —— 多线程实现
    import itertools
    import sys
    import threading
    import time

    def spin(msg, done):
    write, flush = sys.stdout.write, sys.stdout.flush
    for char in itertools.cycle('|/-\\\\'):
    status = f'{char} {msg}'
    write(status)
    flush()
    write('\\x08' * len(status))
    if done.wait(0.1):
    break
    write(' ' * len(status) + '\\x08' * len(status))

    def slow_function():
    time.sleep(3)
    return 42

    def supervisor():
    done = threading.Event()
    spinner = threading.Thread(target=spin, args=('thinking!', done))
    spinner.start()
    result = slow_function()
    done.set()
    spinner.join()
    return result

    if __name__ == '__main__':
    result = supervisor()
    print(f'Answer: {result}')

    两种其他实现(multiprocessing 与 asyncio)的核心任务和 slow_function() 部分与 threading 案例基本相同,但是使用的并发原语不同:multiprocessing.Event / multiprocessing.Process;asyncio.ensure_future / asyncio.event。

    并发模型实现方式创建原语同步原语适用场景
    threading 线程 Thread Event、Lock I/O 密集型(中等并发)
    multiprocessing 进程 Process、Pool Event、Queue CPU 密集型
    asyncio 协程 + 事件循环 ensure_future、Task、async def asyncio.Event I/O 密集型(高并发)

    五、四种通用并发方案

    5.1 并发方案的“大蓝图”

    方案引擎核心障碍适用性
    多线程 + ThreadPool OS 线程 GIL 保护 Python 对象 一定 I/O 并发的任务比例
    多进程 + ProcessPool OS 进程 内存隔离与进程启动成本 CPU 密集型工作
    异步 I/O(asyncio + async/await) 事件循环 必须避免阻塞事件循环的任务 极高密度的 I/O 并发
    从外部调用加速库 C/Go/Rust 外部代码 绕过 GIL 的额外工作 Python 本身性能不够时

    5.2 线程模型基础

    from concurrent.futures import ThreadPoolExecutor
    from time import sleep, perf_counter

    def io_bound_task(task_id, delay):
    sleep(delay)
    return f"Task-{task_id} 完成"

    with ThreadPoolExecutor(max_workers=5) as executor:
    start = perf_counter()
    futures = [executor.submit(io_bound_task, i, 0.5) for i in range(10)]
    results = [f.result() for f in futures]
    print(f"耗时: {perf_counter() start:.2f}秒 —— 如果任务串行执行,耗时会是5秒")

    提交到 ThreadPoolExecutor 的 I/O 等待类任务的并发效果比较好。适合大量 I/O 并发,但不适合大量 CPU 密集计算。

    5.3 进程模型基础

    ProcessPoolExecutor 规避 GIL 限制,能在多核 CPU 上实现真正的并行加速。

    from concurrent.futures import ProcessPoolExecutor

    def cpu_bound_task(n):
    return sum(i ** 2 for i in range(n))

    if __name__ == '__main__':
    with ProcessPoolExecutor(max_workers=4) as executor:
    # map 方法简化提交
    results = list(executor.map(cpu_bound_task, [10**7, 10**7, 10**7, 10**7]))
    print(f"结果: {results}")

    进程之间内存隔离,除了基本参数和返回值,不能共享可变 Python 对象。如需在这些进程之间传递更多数据,可以使用 multiprocessing.Queue 或其他共享内存的方式进行扩展。

    5.4 异步模型基础

    import asyncio

    async def async_io_task(task_id, delay):
    await asyncio.sleep(delay)
    return f"Task-{task_id} 完成"

    async def main():
    tasks = [asyncio.create_task(async_io_task(i, 0.5)) for i in range(10)]
    results = await asyncio.gather(*tasks)
    print(results)

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

    asyncio 在单一线程+事件循环里分发任务,其中核心原语在协程上,await 点交出控制权。优点是可支撑极高密度且长时间等待的 I/O 并发,缺点是需要所有阻塞调用均改用异步版本库。

    5.5 三种模型对比图

    #mermaid-svg-fiAaDoeHO7Xpdvd2{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-fiAaDoeHO7Xpdvd2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .error-icon{fill:#552222;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .marker.cross{stroke:#333333;}#mermaid-svg-fiAaDoeHO7Xpdvd2 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-fiAaDoeHO7Xpdvd2 p{margin:0;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .cluster-label text{fill:#333;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .cluster-label span{color:#333;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .cluster-label span p{background-color:transparent;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .label text,#mermaid-svg-fiAaDoeHO7Xpdvd2 span{fill:#333;color:#333;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .node rect,#mermaid-svg-fiAaDoeHO7Xpdvd2 .node circle,#mermaid-svg-fiAaDoeHO7Xpdvd2 .node ellipse,#mermaid-svg-fiAaDoeHO7Xpdvd2 .node polygon,#mermaid-svg-fiAaDoeHO7Xpdvd2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .rough-node .label text,#mermaid-svg-fiAaDoeHO7Xpdvd2 .node .label text,#mermaid-svg-fiAaDoeHO7Xpdvd2 .image-shape .label,#mermaid-svg-fiAaDoeHO7Xpdvd2 .icon-shape .label{text-anchor:middle;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .rough-node .label,#mermaid-svg-fiAaDoeHO7Xpdvd2 .node .label,#mermaid-svg-fiAaDoeHO7Xpdvd2 .image-shape .label,#mermaid-svg-fiAaDoeHO7Xpdvd2 .icon-shape .label{text-align:center;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .node.clickable{cursor:pointer;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .arrowheadPath{fill:#333333;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-fiAaDoeHO7Xpdvd2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fiAaDoeHO7Xpdvd2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-fiAaDoeHO7Xpdvd2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .cluster text{fill:#333;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .cluster span{color:#333;}#mermaid-svg-fiAaDoeHO7Xpdvd2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-fiAaDoeHO7Xpdvd2 rect.text{fill:none;stroke-width:0;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .icon-shape,#mermaid-svg-fiAaDoeHO7Xpdvd2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .icon-shape p,#mermaid-svg-fiAaDoeHO7Xpdvd2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .icon-shape .label rect,#mermaid-svg-fiAaDoeHO7Xpdvd2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-fiAaDoeHO7Xpdvd2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-fiAaDoeHO7Xpdvd2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-fiAaDoeHO7Xpdvd2 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    选择原则

    少量占用

    大量阻塞

    I/O占用时长?

    线程

    asyncio

    CPU占比?

    多进程

    异步模型

    事件循环

    协程调度

    极高I/O并发密度

    多进程模型

    Python Process

    绕过GIL

    适用CPU密集型

    多线程模型

    Python Thread

    GIL限制

    适合同等I/O并发

    六、多核世界中的 Python

    本章的第 19.7 节(原书 19.6 节)“多核世界的 Python”是一篇零代码、不含库调用的综述部分,完全聚焦于第三方工具和更高层面的架构。书中推荐了以下第三方方案:

    工具/方案类型说明
    Ray 分布式应用库 从单个脚本扩展到整个集群,实现并行、分布式培训等
    Numba JIT 编译器 将 Python 子集编译为执行在 CPU 或 GPU 上的机器码
    Cython 类 Python 的语言 融合 Python 的易用性与 C 语言的速度,并在性能热点处显式增加 C 类型声明
    Dask 分布式计算库 在集群上以大数据和并行计算为目标
    Async Web frameworks 企业 Web 后端 Starlette、FastAPI、Quart、AIOHTTP 高性能异步 Web 框架

    使用 C/C++/Rust/Go 等语言编写 Python 可调用的扩展,可以在绕过 GIL 的同时获得接近于极限性能的多核利用。Numba 和 Cython 是在 Python 生态内实现这一思路的正面案例。

    七、GIL 的局限与对策

    7.1 GIL 详解

    全局解释器锁(Global Interpreter Lock):CPython 确保同时只允许一个线程在解释器中执行 Python 字节码。在多核处理器上,Python 的多线程并发本质是“分时并发”。

    7.2 对策

    应对方法适用范围如何工作
    使用多进程 CPU 密集型任务 每个进程拥有独立的 GIL
    使用 asyncio I/O 密集型任务 事件循环在单线程内交替执行
    C 扩展 混合型任务 调用非 Python 的外部代码时释放 GIL
    Numba/JIT 数值密集型 将 Python 循环编译成 CPU 原语,彻底在解释器外部运行

    八、并发架构决策模型

    #mermaid-svg-pAUCuYuwNSLvrxLT{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-pAUCuYuwNSLvrxLT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-pAUCuYuwNSLvrxLT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-pAUCuYuwNSLvrxLT .error-icon{fill:#552222;}#mermaid-svg-pAUCuYuwNSLvrxLT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-pAUCuYuwNSLvrxLT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-pAUCuYuwNSLvrxLT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-pAUCuYuwNSLvrxLT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-pAUCuYuwNSLvrxLT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-pAUCuYuwNSLvrxLT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-pAUCuYuwNSLvrxLT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-pAUCuYuwNSLvrxLT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-pAUCuYuwNSLvrxLT .marker.cross{stroke:#333333;}#mermaid-svg-pAUCuYuwNSLvrxLT svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-pAUCuYuwNSLvrxLT p{margin:0;}#mermaid-svg-pAUCuYuwNSLvrxLT .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-pAUCuYuwNSLvrxLT .cluster-label text{fill:#333;}#mermaid-svg-pAUCuYuwNSLvrxLT .cluster-label span{color:#333;}#mermaid-svg-pAUCuYuwNSLvrxLT .cluster-label span p{background-color:transparent;}#mermaid-svg-pAUCuYuwNSLvrxLT .label text,#mermaid-svg-pAUCuYuwNSLvrxLT span{fill:#333;color:#333;}#mermaid-svg-pAUCuYuwNSLvrxLT .node rect,#mermaid-svg-pAUCuYuwNSLvrxLT .node circle,#mermaid-svg-pAUCuYuwNSLvrxLT .node ellipse,#mermaid-svg-pAUCuYuwNSLvrxLT .node polygon,#mermaid-svg-pAUCuYuwNSLvrxLT .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-pAUCuYuwNSLvrxLT .rough-node .label text,#mermaid-svg-pAUCuYuwNSLvrxLT .node .label text,#mermaid-svg-pAUCuYuwNSLvrxLT .image-shape .label,#mermaid-svg-pAUCuYuwNSLvrxLT .icon-shape .label{text-anchor:middle;}#mermaid-svg-pAUCuYuwNSLvrxLT .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-pAUCuYuwNSLvrxLT .rough-node .label,#mermaid-svg-pAUCuYuwNSLvrxLT .node .label,#mermaid-svg-pAUCuYuwNSLvrxLT .image-shape .label,#mermaid-svg-pAUCuYuwNSLvrxLT .icon-shape .label{text-align:center;}#mermaid-svg-pAUCuYuwNSLvrxLT .node.clickable{cursor:pointer;}#mermaid-svg-pAUCuYuwNSLvrxLT .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-pAUCuYuwNSLvrxLT .arrowheadPath{fill:#333333;}#mermaid-svg-pAUCuYuwNSLvrxLT .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-pAUCuYuwNSLvrxLT .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-pAUCuYuwNSLvrxLT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pAUCuYuwNSLvrxLT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-pAUCuYuwNSLvrxLT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pAUCuYuwNSLvrxLT .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-pAUCuYuwNSLvrxLT .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-pAUCuYuwNSLvrxLT .cluster text{fill:#333;}#mermaid-svg-pAUCuYuwNSLvrxLT .cluster span{color:#333;}#mermaid-svg-pAUCuYuwNSLvrxLT div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-pAUCuYuwNSLvrxLT .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-pAUCuYuwNSLvrxLT rect.text{fill:none;stroke-width:0;}#mermaid-svg-pAUCuYuwNSLvrxLT .icon-shape,#mermaid-svg-pAUCuYuwNSLvrxLT .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-pAUCuYuwNSLvrxLT .icon-shape p,#mermaid-svg-pAUCuYuwNSLvrxLT .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-pAUCuYuwNSLvrxLT .icon-shape .label rect,#mermaid-svg-pAUCuYuwNSLvrxLT .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-pAUCuYuwNSLvrxLT .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-pAUCuYuwNSLvrxLT .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-pAUCuYuwNSLvrxLT :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    大量I/O等待

    大量CPU计算

    等待短线程切换无感知

    等待长多线程效率低

    小数据频繁通信

    大数据可切分

    识别并发场景

    任务属性

    分析等待时长

    分析数据量

    ThreadPoolExecutor中等并发

    asyncio高并发密度

    ThreadPool + 向量化或者 Numba JIT

    多进程 ProcessPool

    扩展至集群

    Dask / Ray

    九、本章思维导图

    #mermaid-svg-MngLC1wRCNAfVaOS{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MngLC1wRCNAfVaOS .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MngLC1wRCNAfVaOS .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MngLC1wRCNAfVaOS .error-icon{fill:#552222;}#mermaid-svg-MngLC1wRCNAfVaOS .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MngLC1wRCNAfVaOS .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MngLC1wRCNAfVaOS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MngLC1wRCNAfVaOS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MngLC1wRCNAfVaOS .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MngLC1wRCNAfVaOS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MngLC1wRCNAfVaOS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MngLC1wRCNAfVaOS .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MngLC1wRCNAfVaOS .marker.cross{stroke:#333333;}#mermaid-svg-MngLC1wRCNAfVaOS svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MngLC1wRCNAfVaOS p{margin:0;}#mermaid-svg-MngLC1wRCNAfVaOS .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-MngLC1wRCNAfVaOS .cluster-label text{fill:#333;}#mermaid-svg-MngLC1wRCNAfVaOS .cluster-label span{color:#333;}#mermaid-svg-MngLC1wRCNAfVaOS .cluster-label span p{background-color:transparent;}#mermaid-svg-MngLC1wRCNAfVaOS .label text,#mermaid-svg-MngLC1wRCNAfVaOS span{fill:#333;color:#333;}#mermaid-svg-MngLC1wRCNAfVaOS .node rect,#mermaid-svg-MngLC1wRCNAfVaOS .node circle,#mermaid-svg-MngLC1wRCNAfVaOS .node ellipse,#mermaid-svg-MngLC1wRCNAfVaOS .node polygon,#mermaid-svg-MngLC1wRCNAfVaOS .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MngLC1wRCNAfVaOS .rough-node .label text,#mermaid-svg-MngLC1wRCNAfVaOS .node .label text,#mermaid-svg-MngLC1wRCNAfVaOS .image-shape .label,#mermaid-svg-MngLC1wRCNAfVaOS .icon-shape .label{text-anchor:middle;}#mermaid-svg-MngLC1wRCNAfVaOS .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MngLC1wRCNAfVaOS .rough-node .label,#mermaid-svg-MngLC1wRCNAfVaOS .node .label,#mermaid-svg-MngLC1wRCNAfVaOS .image-shape .label,#mermaid-svg-MngLC1wRCNAfVaOS .icon-shape .label{text-align:center;}#mermaid-svg-MngLC1wRCNAfVaOS .node.clickable{cursor:pointer;}#mermaid-svg-MngLC1wRCNAfVaOS .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MngLC1wRCNAfVaOS .arrowheadPath{fill:#333333;}#mermaid-svg-MngLC1wRCNAfVaOS .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MngLC1wRCNAfVaOS .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MngLC1wRCNAfVaOS .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MngLC1wRCNAfVaOS .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MngLC1wRCNAfVaOS .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MngLC1wRCNAfVaOS .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MngLC1wRCNAfVaOS .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MngLC1wRCNAfVaOS .cluster text{fill:#333;}#mermaid-svg-MngLC1wRCNAfVaOS .cluster span{color:#333;}#mermaid-svg-MngLC1wRCNAfVaOS div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MngLC1wRCNAfVaOS .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MngLC1wRCNAfVaOS rect.text{fill:none;stroke-width:0;}#mermaid-svg-MngLC1wRCNAfVaOS .icon-shape,#mermaid-svg-MngLC1wRCNAfVaOS .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MngLC1wRCNAfVaOS .icon-shape p,#mermaid-svg-MngLC1wRCNAfVaOS .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MngLC1wRCNAfVaOS .icon-shape .label rect,#mermaid-svg-MngLC1wRCNAfVaOS .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MngLC1wRCNAfVaOS .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MngLC1wRCNAfVaOS .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MngLC1wRCNAfVaOS :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    第19章:Python并发模型

    术语定义

    并发:同时处理

    并行:同时执行

    三种并发模型

    多线程

    共享内存

    GIL限制

    ThreadPoolExec

    多进程

    隔离内存

    绕过GIL

    ProcessPoolExec

    异步 I/O

    事件循环

    协程async/await

    极高并发密度

    GIL专题

    历史存在

    多进程绕过

    Numba/JIT

    第三方扩展与分布式

    Ray/Dask/cluster

    Starlette/FastAPI

    决策树

    CPU密集型→多进程I/O长等待→asyncioI/O短等待→线程

    十、常见陷阱与最佳实践

    10.1 常见误区

    陷阱分析正确方案
    在多线程中对共享可变对象不加锁 数据竞争导致不可预测的崩溃 使用 threading.Lock 或 RLock
    认为多线程可实现 CPU 密集任务的并行 GIL 会阻止真正的并行 多进程 (ProcessPoolExecutor)
    线程数设得越大越好 过多线程会严重拉低性能 按 min(32, (CPU核心数 + 4)) 的公式设置上限
    在 asyncio 协程中调用阻塞代码 一次阻塞卡死整个事件循环 自定义的同步块转到 run_in_executor
    忽略 Future 状态的异常捕获 返回值挂起的 Future 中寄生的异常可能导致难以调试的失败 调用 future.result() 时必须一律包裹在 try/except 中

    10.2 最佳实践清单

  • I/O 密集型任务的优先选择 asyncio,能提供最高密度的并发且无需处理手动锁。
  • 中等 I/O 并发(特别是涉及已有同步库)使用 ThreadPoolExecutor,更容易与现有同步代码集成。
  • CPU 密集型任务应当使用 ProcessPoolExecutor 来实现多核并行。
  • 始终通过上下文管理器 with 创建 Executor 实例,确保资源被正确回收。
  • 异步项目中警惕阻塞 I/O。
  • 十一、总结

    第 19 章“Python 并发模型”不是一个单纯的 API 使用手册,而是从语言底层开始连通并发与并行编码思想的全书。核心收获:

    • 并发是程序结构的设计能力,并行是程序执行层面的能力。
    • Python 基本并发有三根支柱:多进程(适用 CPU)、多线程(I/O 中等)和 asyncio(异步 I/O 高并发)。
    • 选择并发模型时不是非此即彼——有时会组合使用三种并发方案。
    • concurrent.futures 模块提供的 ThreadPoolExecutor 与 ProcessPoolExecutor 是生产级别推荐使用的主要 API。
    • GIL 不是“Python 不能并行编程”的判词,而是一个“语言设计上的工程约束”。

    十二、思考题

  • 在“四个并发通用方案”中的第三个方案(异步 I/O + 事件循环)中,如果在 await asyncio.sleep() 换成 time.sleep() 代码会有什么后果?为什么?

  • 处于 I/O 密集类的“旋转指针(spinner)”案例更适合哪种模型?如果改为数值计算密集型任务,哪种模型更合适?

  • 在多进程(ProcessPoolExecutor)和 multiprocessing.Process 原始进程之间,如果希望传递一个 NumPy 大数组给 Worker 进程再获得返回值,如何设计能实现最小复制开销?

  • 你已经实现了一个 asyncio Web 服务,其中部分数据读取必须调用数据库官方的同步驱动(例如 psycopg2)——如何避免阻塞服务?

  • 如果我的代码既含 I/O 密集部分又含 CPU 密集部分,如何在 threading 和 multiprocessing 之间进行性能和代码简洁的平衡?

  • 十三、下一章预告

    第 20 章《句法模式匹配》

    在本书第 1 版时,“模式匹配”还是一个不存在于 Python 中的特性。但是 PEP 622 在 Python 3.10 中正式引入模式匹配,把 match/case 语法带入了 Python 核心。第 20 章涵盖了 match 语句的核心语法和真实代码中的最佳实践:

    • 字面量模式、变量模式与 |(OR)模式用法
    • 序列模式匹配与映射模式匹配
    • 守卫(if 条件附加过滤)的使用
    • AS 模式与 _ 通配符模式
    • 自定义类与数据类在模式匹配中的位置模式

    第 20 章将会让你逐步告别狂写一堆 if/elif/elif 的业务逻辑,转为表意清晰、天然分支的模式匹配。


    本文为个人学习笔记,仅用于知识分享。如有错误,欢迎指正。
    👍🏻 点赞 + 收藏 + 分享,让更多开发者看到这篇深度解析!❤️ 如果觉得有用,请给个赞支持一下作者!

    赞(0)
    未经允许不得转载:171主机测评 » 《流畅的Python》读书笔记20: 第四部分 控制流 - Python 并发模型
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址