我想用多线程加速一段纯计算的代码,开了 8 个线程满心以为能快 8 倍,结果不但没快、反而比单线程还慢,因为 Python 有个 GIL、同一时刻只让一个线程真正在算的深度复盘

我有一段 CPU 密集的计算(大量纯数值运算),单线程跑得慢,我想这台机器有 8 核、开 8 个线程并行算不就快 8 倍?于是用 threading 开了 8 个线程分摊计算。结果一测:不但没快 8 倍,反而比单线程还慢,CPU 监控显示始终只有一个核在忙、其他核闲着。复盘才搞懂:CPython 有一个 GIL(全局解释器锁),同一时刻只允许一个线程执行 Python 字节码;我开的 8 个线程没法真正同时执行计算,它们要抢同一把 GIL、一次只有一个在算其他都在等。所以对 CPU 密集任务,Python 多线程不能并行、没有加速,反而因线程切换和抢锁开销比单线程更慢。但多线程对 IO 密集任务有效:线程等 IO 时会释放 GIL,让别的线程干活、重叠等待。我把多线程当成了对任何任务都能并行加速的万能手段,却不知道它受 GIL 约束、只对 IO 密集有效。这篇复盘从故障现场讲到 GIL 是什么、对 CPU 密集与 IO 密集的不同影响、并发模型怎么选,再到 CPU 密集用 multiprocessing 多进程或 numpy、IO 密集用多线程或 asyncio、先判断任务性质的完整正解,以及其他同一手段对不同对象效果不同的坑,和经验有隐含的适用环境和前提、换环境特有约束可能让它失效、迁移经验前要校验适用边界的认知。

我想用多线程加速一段纯计算的代码,开了 8 个线程满心以为能快 8 倍,结果不但没快、反而比单线程还慢,因为 Python 有个 GIL、同一时刻只让一个线程真正在算:一次没搞懂 GIL、误以为多线程对任何任务都能并行加速的深度复盘

那次"多线程优化越优化越慢"的尴尬,让我第一次正视了 Python 的 GIL。我有一段 CPU 密集的计算(大量纯数值运算),单线程跑得慢,我想"这台机器有 8 核啊,开 8 个线程并行算,不就快 8 倍了?",于是兴冲冲用 threading 开了 8 个线程分摊计算。结果一测:不但没快 8 倍,反而比单线程还慢了一点!CPU 监控显示始终只有一个核在忙,其他核闲着。我百思不得其解:线程明明开起来了,怎么不干活?复盘 Python 的并发模型,我才彻底搞懂,后背发凉:问题出在 CPython 有一个 GIL(全局解释器锁,Global Interpreter Lock)——同一时刻,只允许一个线程执行 Python 字节码也就是说,我开的 8 个线程,没法真正"同时"执行计算——它们要抢同一把 GIL,同一时刻只有一个线程拿到锁、在算,其他 7 个都在等;所以对 CPU 密集任务,Python 多线程不能并行(只能在一个核上"轮流"算),没有加速;反而因为线程切换、抢锁的开销,比单线程还略慢;那多线程在 Python 里就没用了吗?不——IO 密集任务(等网络、等磁盘、等数据库),多线程有效:因为一个线程在等 IO 时会释放 GIL,让别的线程去干,这时多线程能"重叠等待"、提升吞吐;把"多线程"当成了"对任何任务都能并行加速"的万能手段,却不知道它受 GIL 约束、只对 IO 密集有效、对 CPU 密集无效。根本原因是:CPython 的 GIL 使同一时刻只有一个线程能执行 Python 字节码,多线程无法并行执行 CPU 密集计算(只能轮流),故 CPU 密集任务多线程不加速甚至因切换开销更慢;多线程只对 IO 密集任务有效(等 IO 时释放 GIL);我误以为多线程对任何任务都能并行加速。问题的根,是没搞懂 GIL——它让多线程不能并行跑 CPU 密集计算;根源是把多线程当成对任何任务都能并行加速的万能手段。这篇就把这次"GIL"的坑,从头到尾复盘一遍。

故障现场:8 个线程,只有一个核在忙

问题在于 GIL 让多线程无法并行执行 CPU 密集计算:

import threading, time

def heavy_compute(n):     # CPU密集: 纯计算
    s = 0
    for i in range(n): s += i * i
    return s

# 我的想法: 8核机器, 开8个线程并行算, 应该快8倍
N = 50_000_000
threads = [threading.Thread(target=heavy_compute, args=(N,)) for _ in range(8)]
t0 = time.time()
for t in threads: t.start()
for t in threads: t.join()
print(f"8线程耗时: {time.time()-t0:.2f}s")
# 实际: 和单线程跑8次差不多, 甚至更慢! CPU监控: 始终只有1个核在忙。

/*
为什么没加速(GIL):
  - CPython有一个 GIL(全局解释器锁): 同一时刻, 只允许【一个】线程执行Python字节码;
  - 所以8个线程不能"同时"算——它们抢同一把GIL, 一次只有一个拿到锁在算, 其他7个在等;
  - 对CPU密集任务: 多线程只是在【一个核上轮流执行】, 没有并行, 没有加速;
  - 反而: 线程切换 + 抢GIL锁的开销, 让它比单线程还略慢。

为什么多线程对IO密集任务【有效】:
  - 当一个线程执行【IO操作】(等网络/磁盘/DB响应)时, 它会【释放GIL】, 让其他线程去执行;
  - 所以IO密集任务: 多个线程的"等待"可以重叠(线程A等网络时, 线程B在干活), 提升吞吐;
  - 这也是为什么 多线程/asyncio 适合 IO 密集(爬虫、网络请求、文件IO)。

怎么真正并行跑CPU密集(绕过GIL):
  - multiprocessing(多进程): 每个进程有【独立的解释器和GIL】, 能真正利用多核并行;
  - C扩展/numpy: 在C层做计算时可以释放GIL(numpy的向量运算就是);
  - 其他实现(无GIL的Python实验性版本)、或换语言做计算密集部分。

★ 核心: CPython的GIL使同一时刻只有一个线程执行Python字节码; 多线程【不能并行跑CPU密集计算】(只轮流)、
  不加速甚至更慢; 多线程只对IO密集有效(等IO时释放GIL); CPU密集要并行用multiprocessing(多进程)。

看着 8 个线程挤在一个核上轮流干、其他 7 个核闲着发呆,我又哭笑不得又恍然:"我一直以为'开多线程 = 多核并行 = 加速',这不是天经地义吗?谁知道 Python 有个 GIL,同一时刻只让一个线程算,我开 8 个线程纯计算,它们只是在排队轮流用一个核……白开了。"这个坑最反直觉的地方在于:"多线程能并行加速"在很多语言(Java/C++/Go)里是对的,这个跨语言的直觉到了 Python 的 CPU 密集场景就失效了;而且它对 IO 密集任务又确实有效(很多人用多线程爬虫尝到甜头),更强化了"多线程万能"的错觉;同一个手段、不同任务,效果天差地别,不懂 GIL 根本想不到下面就来拆解,Python 的并发到底该怎么选。

第一件事:搞懂 GIL 与并发模型的选择

我顺着这次事故,把 GIL 和 Python 并发模型的选择彻底理清了。

GIL 是什么? Python 并发该怎么选?

【核心: CPython的GIL使同一时刻只有一个线程执行Python字节码; 多线程不能并行跑CPU密集(只轮流)、不加速;
   只对IO密集有效(等IO释放GIL); CPU密集用multiprocessing多进程并行; 选并发模型要看任务是CPU还是IO密集】

1. GIL(全局解释器锁)是什么:
   - CPython(主流Python实现)用一把全局锁, 保证同一时刻只有一个线程执行Python字节码;
   - 目的: 简化CPython的内存管理(引用计数)的线程安全, 历史设计;
   - 影响: 多线程无法在多核上"同时"执行Python代码——CPU密集任务多线程不能并行。

2. 对不同任务的影响:
   - CPU密集(纯计算: 数值运算、图像处理、加密): 多线程【无加速】(抢GIL轮流跑一个核), 甚至更慢;
   - IO密集(等网络/磁盘/DB: 爬虫、请求、文件): 多线程【有效】——线程等IO时释放GIL, 别的线程能干活, 重叠等待。

3. 并发模型怎么选(关键是看任务性质):
   ① CPU密集 → 用 multiprocessing(多进程): 每进程独立解释器+GIL, 真正多核并行; 或用numpy/C扩展;
   ② IO密集 → 用 多线程(threading) 或 asyncio(协程): 重叠等待, 提升吞吐;
      - 海量IO并发(几千连接)用 asyncio(更轻量); 中等用线程池也行;
   ③ 混合 → 进程池处理CPU部分 + 异步/线程处理IO部分。

4. 常见误区:
   - 以为"多线程=多核并行加速"(跨语言直觉, 在Python CPU密集上错);
   - 以为"GIL让Python多线程完全没用"(错, IO密集很有用);
   - 以为"asyncio能加速CPU密集"(错, 它也是单线程协程, 只擅长IO并发);
   - CPU密集时用了线程池还纳闷为啥不快——根源是GIL。

5. 本质: 一个手段对不同性质的对象, 效果可能截然不同; 要理解它的适用条件和底层约束
   - "多线程"不是"万能加速器"; 它的效果取决于"任务是CPU密集还是IO密集"和"GIL的约束";
   - 用一个工具/手段前, 要搞清"它在什么条件下有效、什么条件下无效", 而非套用一个笼统的印象。

一句话: CPython的GIL使同一时刻只有一个线程执行Python字节码、多线程不能并行跑CPU密集(只轮流)、不加速;
   只对IO密集有效; CPU密集要并行用multiprocessing多进程; 选并发模型先看任务是CPU密集还是IO密集。

这套认知,是整个坑的根。GIL 是什么:CPython 用一把全局锁保证同一时刻只有一个线程执行 Python 字节码(为简化引用计数的线程安全),导致多线程无法在多核上同时执行 Python 代码对不同任务:CPU 密集(纯计算)多线程无加速甚至更慢;IO 密集(等网络/磁盘)多线程有效(等 IO 时释放 GIL)怎么选:CPU 密集用 multiprocessing 多进程(各自独立 GIL、真并行)或 numpy/C 扩展;IO 密集用多线程或 asyncio;混合则进程处理 CPU + 异步处理 IO常见误区:多线程=多核并行(Python CPU 密集上错)、GIL 让多线程完全没用(错,IO 有用)、asyncio 能加速 CPU 密集(错)本质:一个手段对不同性质的对象效果可能截然不同;要理解它的适用条件和底层约束,而非套用笼统印象一句话:CPython 的 GIL 使同一时刻只有一个线程执行 Python 字节码、多线程不能并行跑 CPU 密集(只轮流)、不加速;只对 IO 密集有效;CPU 密集要并行用 multiprocessing 多进程;选并发模型先看任务是 CPU 密集还是 IO 密集。

第二件事:正解——CPU 密集用多进程、IO 密集用多线程/异步

知道了 GIL,正解就清楚了:按任务性质选并发模型——CPU 密集用多进程绕过 GIL。

# 正解1: CPU密集 → multiprocessing 多进程(每进程独立GIL, 真并行)——本次该用的
from multiprocessing import Pool
def heavy_compute(n):
    s = 0
    for i in range(n): s += i * i
    return s

if __name__ == "__main__":
    with Pool(8) as pool:                          # 8个进程, 各跑在一个核上, 真并行
        results = pool.map(heavy_compute, [N] * 8)  # CPU密集任务这才真的快了!
# 多进程绕过GIL(各进程独立解释器), 能利用多核; 代价: 进程更重、有进程间通信开销。

# 正解2: IO密集 → 多线程(threading)/线程池(线程等IO时释放GIL, 重叠等待)
from concurrent.futures import ThreadPoolExecutor
def fetch(url):
    return requests.get(url).text                  # IO密集: 等网络

with ThreadPoolExecutor(max_workers=20) as ex:     # 20个线程并发请求
    results = list(ex.map(fetch, urls))            # 线程等网络时释放GIL, 多个请求重叠等待, 快!

# 正解3: 海量IO并发 → asyncio(协程, 更轻量)
import asyncio, aiohttp
async def fetch_async(session, url):
    async with session.get(url) as resp: return await resp.text()
async def main(urls):
    async with aiohttp.ClientSession() as s:
        return await asyncio.gather(*[fetch_async(s, u) for u in urls])  # 几千并发IO也轻松

# 正解4: 计算密集且能向量化 → 用 numpy(底层C, 释放GIL)
import numpy as np
arr = np.arange(N)
result = np.sum(arr * arr)                         # numpy向量运算在C层做, 不受GIL限、且快得多

# 正解5: 选之前先判断任务性质
#   - 任务大部分时间在"算"(CPU忙) → CPU密集 → multiprocessing / numpy / C扩展;
#   - 任务大部分时间在"等"(等网络/磁盘/DB, CPU闲) → IO密集 → threading / asyncio;
#   - 用 profiler / 看CPU是否打满 来判断。

# 反例(别这样):
# - CPU密集任务开一堆线程(本次): GIL下不并行, 白开还更慢;
# - IO密集任务硬上多进程: 进程太重、开销大, 不如线程/异步轻量。

# 核心: 按任务性质选——CPU密集用multiprocessing多进程(绕GIL真并行)或numpy; IO密集用threading/asyncio
#   (等IO释放GIL重叠等待); 先判断任务是CPU密集还是IO密集, 再选对的并发模型。

这套正解的关键,是先判断任务是"CPU 密集"还是"IO 密集",再选对应的并发模型CPU 密集用多进程:multiprocessing 每进程独立 GIL、能真正利用多核并行——这正是本次该用的(我误用了多线程)。IO 密集用多线程/线程池:线程等 IO 时释放 GIL,多个请求重叠等待、提升吞吐。海量 IO 并发用 asyncio:协程更轻量,几千并发也轻松。能向量化的计算用 numpy:底层 C 做、释放 GIL、还快得多。选之前先判断任务性质:看 CPU 是否打满——大部分时间在算就 CPU 密集、在等就 IO 密集。

第三件事:其他几个"手段对不同对象效果不同"的坑

顺着这次 GIL,我把"同一手段对不同性质的对象效果截然不同"的几类坑也一并理了:

几类"同一手段对不同对象效果不同, 却套用笼统印象"的坑:

坑1: 多线程加速(本篇)——对IO密集有效、CPU密集无效(GIL); 看任务性质选。

坑2: 加缓存提速——对"读多写少、热点集中"有效; 对"写多/无热点/强一致"反而添乱(同550);
   要看数据访问模式。

坑3: 加索引提速——对"高选择性查询"有效; 对"低选择性/写多"可能反拖慢写入(同342/582);
   看查询模式和读写比。

坑4: 异步化——对IO密集提升吞吐; 对CPU密集没用(asyncio单线程); 别拿asyncio跑纯计算。

坑5: 加机器/水平扩展——对"无状态、可并行"的服务有效; 对"有状态/串行依赖/单点瓶颈"无效;
   要看是否真能并行。

坑6: 重试——对"偶发、瞬时"故障有效; 对"系统性过载"有害(放大, 同583); 看故障性质。

坑7: 分库分表——对"数据量大、可按维度切分"有效; 数据量不大时徒增复杂度; 看实际规模。

共同的根: 几乎每个"优化/加速/扩展手段"(多线程、缓存、索引、异步、加机器、重试、分库),
   都有它【适用的条件和对象性质】; 它对"符合条件的情况"有效, 对"不符合的"无效甚至有害;
   把一个手段当成"对任何情况都管用"的万能药、不看适用条件就套用, 往往无效、甚至帮倒忙——
   要理解每个手段"在什么条件下、对什么性质的任务/数据才有效"。

这些坑看似不同,根却是同一个:几乎每个"优化/加速/扩展手段"(多线程、缓存、索引、异步、加机器、重试),都有它适用的条件和对象性质;它对"符合条件的情况"有效,对"不符合的"无效甚至有害;把一个手段当成"对任何情况都管用"的万能药、不看适用条件就套用,往往无效甚至帮倒忙认清这个根("每个手段有其适用条件,用前先判断对象性质是否匹配"),才不会盲目套用"万能优化"。

第四件事:任务性质 vs 并发模型 / 各方案对比——两张对照表

我把任务性质与并发模型的匹配、以及各方案对比,整理成对照表,贴在了团队的 Python 规范里:

任务性质 多线程 多进程 asyncio
CPU 密集(纯计算) ✗ 无加速(GIL) ✓ 真并行 ✗ 单线程协程无用
IO 密集(网络/磁盘) ✓ 有效 △ 可但重 ✓ 海量并发更佳
能向量化的计算 用 numpy(释放 GIL)
方案 绕过 GIL? 适用 / 代价
threading 多线程 IO 密集;CPU 密集无效
multiprocessing 多进程 是(各自 GIL) CPU 密集真并行;进程重、有 IPC 开销
asyncio 协程 单线程 海量 IO 并发;不能加速 CPU
numpy / C 扩展 计算时释放 向量化计算,快且并行

这两张表的核心,第一张是CPU 密集只有多进程(或 numpy)能真正并行加速,多线程和 asyncio 都无用;IO 密集则多线程/asyncio 有效;第二张是要"真正利用多核跑 CPU 密集",必须用能绕过 GIL的方案(多进程/numpy)。记住一条:选并发模型前,先回答一个问题——"我的任务大部分时间在''还是在''?"算就多进程,等就多线程/异步。

第五件事:关于 Python 并发的几组容易想当然的认知

这次事故也让我厘清了几组关于 GIL 和并发的、容易想当然的概念:

直觉以为 实际上
多线程 = 多核并行 = 加速 GIL 下 CPU 密集多线程不并行、不加速
开 8 个线程就用上 8 个核 CPU 密集时只有一个核在轮流忙
GIL 让 Python 多线程完全没用 IO 密集任务多线程很有用
asyncio 能加速 CPU 密集 它是单线程协程,只擅长 IO 并发
多进程和多线程差不多 多进程绕 GIL 能真并行,但更重
并发模型随便选都行 选错(CPU 密集用线程)完全无效
跨语言的多线程直觉在 Python 也成立 GIL 让 CPU 密集场景的直觉失效

这张表里,我栽的是第一行和第二行:把"多线程=多核并行=加速"这个跨语言的直觉,直接套到了 Python 的 CPU 密集任务上,开 8 个线程却只用上一个核、还更慢厘清这些,核心是一个意识:"多线程能不能并行加速"在 Python 里取决于两件事——任务是 CPU 密集还是 IO 密集、以及 GIL 的约束;同一个"多线程",对 IO 密集是良药、对 CPU 密集是无用甚至有害;别把一个手段的笼统印象当普适真理,要理解它在不同条件下的真实效果。

第六件事:做并发/性能优化时,我现在的自检习惯

现在每当我想用并发加速 Python 代码,我都会先按这张图问自己:

这张图的精髓,是"先判断在算还是在等:在算用多进程/numpy、在等用多线程/异步"第一步永远是判断 CPU 密集还是 IO 密集(看 CPU 是否打满),再据此选对应的并发模型这套习惯,让我从"加速就开多线程"变成了"先看任务性质再选模型"——核心始终是:CPython 的 GIL 使多线程不能并行跑 CPU 密集计算、不加速;多线程只对 IO 密集有效;CPU 密集要并行用 multiprocessing 多进程;选并发模型先看任务是 CPU 密集还是 IO 密集。

我立下的几条规矩

这场"多线程加速 CPU 密集反而更慢"的事故,换来了我写 Python 并发时,刻进骨子里的几条铁律:

  1. CPython 有 GIL:同一时刻只有一个线程执行 Python 字节码,多线程无法并行执行 Python 代码。
  2. CPU 密集任务(纯计算)用多线程不加速,甚至因切换/抢锁开销比单线程更慢。
  3. IO 密集任务(等网络/磁盘/DB)多线程有效:线程等 IO 时释放 GIL,可重叠等待提升吞吐。
  4. CPU 密集要真正并行用 multiprocessing(多进程,各自独立 GIL),或用 numpy/C 扩展(释放 GIL)。
  5. 海量 IO 并发用 asyncio(协程更轻量);asyncio 也是单线程,不能加速 CPU 密集。
  6. 选并发模型前,先判断任务是 CPU 密集还是 IO 密集(看 CPU 是否打满、看在算还是在等)。
  7. 别把"多线程=并行加速"的跨语言直觉,无脑套到 Python 的 CPU 密集任务上。

附:一段判断"CPU 密集还是 IO 密集"的实测

借这次的坑,我整理了一个简单的对比实测,帮团队在选并发模型前,先用数据判断任务到底是 CPU 密集还是 IO 密集,以及不同模型的实际效果。

import time, threading
from multiprocessing import Pool
from concurrent.futures import ThreadPoolExecutor

def cpu_task(n):                    # CPU密集: 纯计算
    s = 0
    for i in range(n): s += i * i
    return s

# 对比1: CPU密集任务, 单线程 vs 多线程 vs 多进程
N, K = 30_000_000, 4
def bench(label, fn):
    t = time.time(); fn(); print(f"{label}: {time.time()-t:.2f}s")

bench("单线程顺序", lambda: [cpu_task(N) for _ in range(K)])
def use_threads():
    ts = [threading.Thread(target=cpu_task, args=(N,)) for _ in range(K)]
    for t in ts: t.start()
    for t in ts: t.join()
bench("多线程(GIL下不并行)", use_threads)        # ≈ 单线程, 甚至更慢
if __name__ == "__main__":
    bench("多进程(真并行)", lambda: Pool(K).map(cpu_task, [N]*K))  # 明显更快(接近 1/K)

# 结论(典型): 单线程 ≈ 多线程(GIL!) >> 多进程(真并行加速);
#   多线程对CPU密集毫无帮助, 数字会清清楚楚告诉你。

# 判断任务性质的简单方法:
#   - 跑任务时看 CPU 利用率: 单核打满(其他闲)且持续 → CPU密集;
#     CPU大部分时间低、卡在等待(网络/磁盘) → IO密集;
#   - 或用 profiler 看时间花在"计算"还是"等待(IO/sleep)"上。

# 原则: "这是CPU密集还是IO密集"不靠猜, 靠【实测/观测】(基准对比 + 看CPU利用率);
#   判断对了, 才能选对并发模型——别在不知道任务性质的情况下盲目套用某种并发手段。

这段实测的价值,在于它把"多线程对 CPU 密集到底有没有用"这个争论,变成了一眼可见的数字(多线程 ≈ 单线程,多进程才真快),也教会团队用"看 CPU 利用率"这个简单观测来判断任务性质。它体现的原则是:"这是 CPU 密集还是 IO 密集"不该靠猜,而该靠实测和观测——判断对了任务的性质,才谈得上选对并发模型;在没搞清任务性质之前就套用某种并发手段,纯属碰运气。

写在最后

回头看,这场由"不懂 GIL、误用多线程加速 CPU 密集"引发的尴尬,真正教给我的,远不止"CPU 密集用多进程"这一个技巧。它让我对"一个我们从别处学来、用得很熟的'解决办法'(多线程并行加速), 在换了一个具体环境(Python + CPU 密集)后, 可能因为这个环境特有的约束(GIL)而完全失效、甚至帮倒忙; 而我们却带着旧环境的直觉, 想当然地以为它到哪都管用",有了一次刻骨的体会。我栽跟头,是因为我把一个"在别的语言里成立的经验"(多线程 = 多核并行 = 加速), 当成了"放之四海而皆准的真理"——我没问"在 Python 里、对这种任务、这条经验还成立吗";可 Python 有它特有的约束(GIL): 这个约束恰恰打破了"多线程能并行执行计算"这个我视为天经地义的前提;于是我那套在别处屡试不爽的"开多线程加速", 在这个特定环境的特定任务上, 不仅没用, 还因为额外的开销而更慢——经验没错, 错的是我不加辨别地把它搬到了一个它不适用的环境里这让我领悟到一个关于"经验、环境与适用边界"的深刻认知:几乎每一条"有用的经验/手段/最佳实践", 都有它隐含的'适用环境和前提'——它是在某些条件下被验证有效的; 当环境、约束、对象的性质变了, 它可能就不再适用;而最容易出错的, 是我们对'用得太熟的经验'失去了警觉: 正因为它"一直管用", 我们就忘了它'也是有条件的', 把它当成无条件的真理, 不假思索地搬到新环境里——结果在新环境特有的约束下栽跟头;真正的高手, 不只是"掌握了很多经验", 更是"清楚每条经验的适用边界, 换环境时会主动问'这条经验在这里还成立吗'"这给了我一种迁移经验时的清醒:每当我想把一条"在别处有效的经验/手段"应用到新场景时,要警觉地问"这条经验当初是在什么条件下有效的?新场景满足这些条件吗?这里有没有'它没考虑过的特有约束'(像 GIL)会让它失效?"——不把熟悉的经验当成无条件的真理无脑套用, 而是带着对'适用边界'的辨别去迁移它;"识别每条经验的隐含适用条件、换环境时主动校验它是否仍成立",是避免'用对的经验在错的地方栽跟头'的关键认清经验有隐含的适用环境和前提、换环境特有约束可能让它失效、迁移经验前要校验适用边界——这,是我用一次 GIL 误用多线程的事故,换来的、关于 Python、也关于如何辨别经验适用边界的、最朴素也最深刻的领悟。如果这篇复盘,能让你下次想"开多线程加速"之前,先问一句"我这是 CPU 密集还是 IO 密集、Python 的 GIL 会不会让多线程在这儿失效",那我对着那 8 个挤在一个核上、还更慢的线程发愣的这段时间,就值了。

—— 别看了 · 2026
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理 邮箱1846861578@qq.com。
技术教程

我搭了个多 Agent 系统让几个智能体协作干活,以为人多力量大会更强,结果它们要么抢着做同一件事、要么都以为对方会做而漏了、甚至 A 等 B 的结果 B 又在等 A 直接卡死的深度复盘

2026-6-3 2:47:14

技术教程

我想判断一个计算结果是不是 NaN,顺手写了 x === NaN,结果它永远返回 false、NaN 一路混了过去到处传播,因为 NaN 是唯一一个连等于它自己都不成立的值的深度复盘

2026-6-3 2:59:10

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索