Python多线程无法利用多核怎么办_从GIL原理到Multiprocessing重构

ThreadPoolExecutor不能突破GIL,CPU密集型任务下多线程实为串行执行,仅单核满载;真正压满多核须改用ProcessPoolExecutor等进程模型。

ThreadPoolExecutor 不能突破 GIL,CPU 密集型任务用它只会卡在一个核上跑 —— 想真正压满多核,必须换进程模型。

为什么 threadingThreadPoolExecutor 都跑不满多核

CPython 的 GIL 是个独占锁:任意时刻只允许一个线程执行 Python 字节码。哪怕你启了 8 个线程,在纯计算场景下(比如循环、数学运算),它们实际是轮流抢锁、串行执行的。

常见错误现象:

  • psutil.cpu_percent() 显示单核 100%,其余核长期低于 5%
  • 任务耗时几乎不随线程数增加而下降,甚至变慢(上下文切换开销)
  • top 或活动监视器看,Python 进程只有一个 CPU 时间片在增长

注意:I/O 密集型任务(如 HTTP 请求、文件读写)不受此限,因为系统调用会主动释放 GIL,此时多线程仍有效。但只要代码主体是计算,就别指望它并行。

multiprocessing 替代 threading 的关键改法

进程间不共享 GIL,每个子进程拥有独立解释器和内存空间,天然支持多核并行。但要注意接口和数据传递方式变化:

  • 函数必须可被 pickle 序列化(不能是嵌套函数、lambda、类实例方法)
  • 参数和返回值也得能被 pickle,大对象传参前考虑用 multiprocessing.shared_memoryqueue
  • if __name__ == "__main__": 保护必不可少,否则 Windows/macOS 下会反复 fork 主模块
  • 启动方式推荐 mp.set_start_method('spawn'),尤其涉及多线程或 C 扩展时,避免 fork 引发的死锁或状态污染

示例对比(质数判断):

百灵大模型

蚂蚁集团自研的多模态AI大模型系列

下载

# 错误:用 ThreadPoolExecutor 处理 CPU 密集型任务
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=4) as ex:
    list(ex.map(is_prime, numbers))  # 实际还是单核忙

正确:换成 ProcessPoolExecutor

from concurrent.futures import ProcessPoolExecutor with ProcessPoolExecutor(max_workers=4) as ex: list(ex.map(is_prime, numbers)) # 四核齐动

multiprocessing.PoolProcessPoolExecutor 怎么选

两者底层都基于 multiprocessing,区别在抽象层级和使用习惯:

  • Pool 更底层,提供 apply/map/starmap 等同步/异步接口,适合批量同构任务
  • ProcessPoolExecutorconcurrent.futures 统一接口的一部分,与 ThreadPoolExecutor 行为一致,便于在 I/O/CPU 任务间切换(只需改 import 和类名)
  • 若需细粒度控制子进程生命周期(如手动管理 worker 进程、设置超时、取消任务),优先用 ProcessPoolExecutor
  • 若已有大量基于 Pool 的老代码,且无 executor 特性需求,不必强改

性能差异极小,选哪个主要看团队编码规范和后续扩展性。

容易被忽略的坑:数据序列化开销和内存复制

多进程不是银弹。每次传参、取结果都要走 pickle → 序列化 → 进程间通信 → 反序列化流程:

  • 传入一个 100MB 的 numpy.ndarray,会被完整拷贝 4 次(4 个 worker 各一份),而不是共享
  • 频繁小任务 + 大参数 = 开销反超收益,此时应合并任务粒度,或改用 multiprocessing.shared_memory(Python 3.8+)
  • Windows 下默认启动方式是 spawn,但 Linux/macOS 默认是 fork;若子进程里用了多线程或某些 C 库(如 OpenMP),fork 可能引发死锁,务必显式设为 spawn

重构时最常漏掉的,就是没测数据传输成本 —— 先用 time.perf_counter() 分段打点,确认瓶颈真在计算,而不是 pickle 或 IPC 上。

相关推荐:

10 核 AMD Zen 6 APU 样品跑分曝光:单核比 Ryzen AI 9 365 快 29%、多核快 22%

感谢网友 华南吴彦祖 的线索投递! 7 月 9 日消息,科技媒体 Wccftech 昨日(7 月 8 日)发布博文,报道称 AMD 下一代 Medusa Point“Zen 6”APU 样品现身 GeekBench 跑分库,编号为“100-000001713-33_N”,配置为 10 核 20 线程,采用“Zen 6”架构,4+6 集群组合。根据跑分页面信息,该样品芯片搭载于 Plum-MDS1 ...

重构:阿塔提斯可缇卡技能解析

重构:阿塔提斯可缇卡技能及天赋一览,可缇卡适合和远击简谐智能在下路发育保护C位,对线时利用长手和护盾优势频繁和敌人换血消耗,到后游戏中后期超大范围的大招释放得当可以为队伍扭转战局。 重构:阿塔提斯可缇卡技能解析: 一、定位: 可缇卡是一位功能性协导,能够为队友提供少量治疗、护盾、加速以及普攻伤害,同时拥有一定的消耗能力,并能提供大范围的控制效果。 二、分路: 可缇卡适合和远击简谐智能在下路发育保护...

重构:阿塔提斯八咫技能介绍

重构阿塔提斯八咫技能属性一览,八咫适合在上路进行对抗,并能与大部分重位和战体制衡,尽快提升等级积累装备,积极参与团战在队伍的最前端吸收伤害,利用移速和远距离控制限制对方主要输出。 重构:阿塔提斯八咫技能介绍: 一、定位 八咫的定位是重卫,由于被动的存在本身的抗性较低但拥有很高的生命值,同时他还拥有不俗的输出与回复能力,在团战中不仅能在前排吸收成吨的伤害,还能提供一定的控制和AOE输出。 推荐分路 ...

重构:阿塔提斯伊贺葵技能解析

重构阿塔提斯伊贺葵技能介绍,伊贺葵适合走下路由协导保护发育,伊贺葵的前期主要依靠1技能消耗对线,对拼能力并不强势,需要解锁大招后配合多个分身和灵活性才能打出输出。优先发育,到游戏后期接管比赛。 重构:阿塔提斯伊贺葵技能解析: 定位: 伊贺葵的定位是远击,她在学习3技能后是非常灵活的简谐智能,拥有普攻可位移并且可以与分身换位的手段,分身还能协同攻击目标叠加印记,可在短时间内快速触发印记伤害,她在游戏...

重构:阿塔提斯终末之役模式玩法介绍

重构阿塔提斯终末之役模式怎么玩,这是一场紧张刺激的12人独立混战模式,最终存活的向导将赢得「未来夜莺」的荣誉!玩家通过单人匹配进入战场,每位向导均为独立阵营,目标是在毒圈与其他向导的威胁中活到最后。 重构:阿塔提斯终末之役模式玩法介绍: 一、终末之役模式 二、核心规则 【生存至上】通过单人匹配进入战场,每位向导均为独立阵营,目标是在毒圈与其他向导的威胁中活到最后。 【出生选择】开局可选择单路安全区...

GitHub Copilot实战案例:利用AI对话快速重构老旧项目代码

GitHub Copilot可通过/explain理解旧代码、/refactor重构、注释指令生成代码、跨文件分析技术债、测试先行驱动重构五种路径高效维护老旧项目。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜ 如果您正在维护一个多年未更新的老旧项目,面对大量嵌套逻辑、硬编码值和缺失文档的代码,手动梳理与重构耗时且易错。以下是利用GitHu...
· AI · 238232

Cursor重构函数提示词怎么写才能保持输入输出不变

必须锁定接口契约、禁止修改调用侧可见行为、提供与原逻辑一致的测试用例:明确写出函数签名与docstring,禁止更改函数名、参数顺序、默认值、返回类型及边界响应,附准确断言示例。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜ 要让Cursor在重构函数时严格保持原有输入输出行为不变,关键在于提示词必须锁定接口契约、禁止修改调用侧可见部分,并...
· AI · 78311

QoderWake正则搜索配置技巧:大规模重构代码必备

QoderWake高精度正则搜索需适配工程上下文并启用语义增强:一、区分search()(全局扫描)与match()(行首严格匹配);二、注入语言感知边界规避注释/字符串误匹配;三、采用多阶段工具链粗筛→精滤;四、启用MCP跨源联动扩展搜索边界。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜ 如果您在使用 QoderWake 进行大规模代码...