当前位置:首页 > 文章列表 > 文章 > python教程 > Python InterpreterPoolExecutor怎样并行执行纯 Python 计算

Python InterpreterPoolExecutor怎样并行执行纯 Python 计算

来源:17golang原创 2026-11-05 00:19:56 0浏览 收藏

如果任务主要消耗 CPU,而且计算逻辑是纯 Python,Python 3.14 可以用 concurrent.futures.InterpreterPoolExecutor 把任务交给多个隔离解释器执行。它不是把一个可变对象同时交给多个线程,而是让每个 worker 在线程中拥有自己的解释器和 GIL,再通过可序列化的参数和返回值交换数据。

下面用一个小型“批量计算任务”说明完整写法:函数放在模块顶层,参数和结果保持简单,主线程负责提交任务、收集 Future,并在异常时保留任务编号。示例不承诺固定加速比例,实际效果要看任务大小、CPU 核数、序列化成本和依赖库是否支持多解释器。

官方地址:https://docs.python.org/3/library/concurrent.futures.html

InterpreterPoolExecutor 解决的是什么问题

ThreadPoolExecutor 适合大量 I/O 等待,但在默认 CPython 中,多个线程执行纯 Python 字节码时会受到同一个 GIL 的限制。InterpreterPoolExecutor 继承了线程池接口,却让每个工作线程绑定一个独立解释器;每个解释器有自己的运行时状态和 GIL,因此纯 Python 计算有机会在多个 CPU 核心上同时运行。

这里的关键词是“隔离”。不同解释器不会自动共享导入模块、sys、builtins 或可变对象。提交的可调用对象、参数和返回值会跨越序列化边界;这使数据交换更明确,也意味着函数、参数和结果不能随意依赖主解释器中的隐式状态。

InterpreterPoolExecutor 将任务提交到多个隔离解释器并返回结果的结构说明图
图1:InterpreterPoolExecutor 的隔离解释器与任务返回关系说明图,不是运行截图。

先准备 Python 3.14 和一个可序列化的任务

InterpreterPoolExecutor 是 Python 3.14 新增的执行器。先确认解释器版本,再创建一个独立目录。示例中不使用 lambda、嵌套函数或只能在交互式环境中找到的函数,这些写法容易在跨解释器传递时遇到序列化问题。

# 创建项目目录并进入项目,示例使用 Python 3.14 或更高版本
mkdir interpreter-pool-demo
cd interpreter-pool-demo

# 检查当前解释器版本,版本过低时不会提供 InterpreterPoolExecutor
python --version

# 创建主脚本;把后面的代码保存为 main.py
touch main.py

本例的任务函数会计算一段整数区间内的平方和。它故意只接收整数并返回整数,便于把注意力放在并发模型和数据边界上,而不是外部服务或文件状态上。

用多个隔离解释器执行纯 Python 计算

把下面代码保存到 main.py。sum_of_squares 位于模块顶层,run_batch 用 submit 生成 Future,再逐个读取结果。max_workers 只是示例值,不应当被当成所有机器的最佳配置。

from concurrent.futures import InterpreterPoolExecutor


def sum_of_squares(start: int, stop: int) -> int:
    """计算左闭右开区间内的平方和。"""
    # 任务只使用参数和局部变量,避免依赖主解释器中的可变全局状态。
    return sum(value * value for value in range(start, stop))


def run_batch(ranges: list[tuple[int, int]]) -> list[tuple[int, int]]:
    """提交一批计算,并返回成功结果与失败任务的位置。"""
    results: list[tuple[int, int]] = []

    # with 负责等待任务结束并回收工作线程,避免遗漏 executor.shutdown()。
    with InterpreterPoolExecutor(max_workers=4) as executor:
        futures = {
            # 顶层函数、整数参数都可以跨越解释器的序列化边界。
            executor.submit(sum_of_squares, start, stop): (start, stop)
            for start, stop in ranges
        }

        for future, task_range in futures.items():
            try:
                # result() 会等待该任务,并在 worker 抛错时重新抛出异常。
                results.append((task_range[0], future.result()))
            except Exception as exc:
                # 保留任务范围,便于调用方定位是哪一个输入失败。
                print(f"任务 {task_range} 失败:{exc}")

    return results


if __name__ == "__main__":
    # 用多个互不依赖的区间模拟批量 CPU 计算任务。
    task_ranges = [(1, 200_000), (200_000, 400_000), (400_000, 600_000)]
    completed = run_batch(task_ranges)
    print(f"成功完成 {len(completed)} 个任务")

这段代码的关键不在于把 ThreadPoolExecutor 换成一个更长的类名,而在于任务边界变得明确:worker 不读取主解释器里的列表,也不修改共享字典;主线程只通过参数传入数据,再通过返回值拿回结果。

运行时要关注哪些结果

运行脚本:

# 从项目目录启动主脚本,输出只用于确认任务已完成
python main.py

示例输出的重点是任务数量和异常信息,而不是某一个固定耗时。任务太小的时候,创建解释器、导入模块和序列化参数的成本可能抵消并行收益;任务足够大且彼此独立时,才更适合测试多个 worker 的效果。

如果要让结果顺序与输入顺序一致,可以继续使用按提交顺序读取的 future.result();如果更关心哪个任务先完成,可以改用 concurrent.futures.as_completed,但仍要保留 Future 与输入的映射。两种写法都不会改变解释器之间的隔离规则。

pickle 边界决定了哪些代码能提交

submit() 和 map() 会把可调用对象与参数序列化后发送到 worker 解释器,返回值也会序列化回来。因此,下面几条是实际项目中最容易踩到的边界:

  • 函数尽量定义在模块顶层,不要直接提交 lambda 或局部嵌套函数。
  • 参数和返回值使用数字、字符串、字节串、列表、元组、字典等可序列化数据;不要把打开的文件句柄、锁或连接对象当作参数传入。
  • worker 需要的模块要在 worker 自己的解释器中导入,主解释器已经导入并不代表其他解释器也有同一个模块对象。
  • 不要依赖可变全局变量在多个 worker 之间自动同步;如果需要汇总,就让 worker 返回结果,再由主解释器统一合并。

这也是为什么“把计算函数写得纯一些”很重要:函数接收输入、完成计算、返回结果,边界清晰时才容易迁移到解释器池。Python 官方文档也提醒,第三方扩展模块不一定已经适配多解释器,使用科学计算或原生扩展依赖时要单独确认兼容性。

它和线程池、进程池到底怎么选

三个执行器都提供相似的 Future 接口,但资源模型和通信成本不同。可以先用任务特征做判断:

执行器适合的任务主要边界
ThreadPoolExecutor网络、磁盘、等待时间较多的 I/O 任务纯 Python 字节码通常共享同一个解释器和 GIL
InterpreterPoolExecutor彼此独立、可序列化、偏纯 Python 的 CPU 计算解释器隔离,参数与返回值跨 pickle 边界,启动和内存成本需要评估
ProcessPoolExecutor需要进程隔离,或已有成熟多进程部署方式的 CPU 任务进程启动与进程间通信成本更高,同样要求可序列化并注意主模块可导入
ThreadPoolExecutor、InterpreterPoolExecutor 与 ProcessPoolExecutor 的 GIL 和数据边界对比图
图2:三种 Python 并发执行器的数据边界对比结构图,不是运行截图。

选择时不要只看“能不能多核”。还要把任务拆分粒度、参数大小、模块导入时间、内存预算、异常恢复方式和第三方扩展兼容性放到同一张决策表里。对于很小的计算,串行版本可能更简单;对于 I/O 等待,线程池往往更合适;对于需要强进程边界的场景,进程池仍然是直接选项。

常见问题与上线前检查

为什么代码在 Python 3.13 上找不到这个类?

因为 InterpreterPoolExecutor 在 Python 3.14 才加入标准库。先确认实际启动脚本使用的解释器版本,而不是只确认系统里安装过某个新版本。

为什么 worker 看不到主线程刚导入的模块或变量?

这是隔离设计的一部分。把 worker 需要的导入写在任务模块中,把必要数据作为参数显式传入;不要把主解释器的可变全局状态当成共享缓存。

为什么换成 InterpreterPoolExecutor 后反而变慢?

常见原因是单个任务太小、任务参数太大、worker 初始化和导入成本过高,或者第三方库没有很好地适配多解释器。先增大单个任务的工作量,再分别记录串行、线程池和解释器池的耗时与内存,避免用一次运行结果下结论。

上线前可以检查什么?

  • 运行环境确实是 Python 3.14 或更高版本。
  • 提交函数在模块顶层定义,参数和返回值可序列化。
  • worker 所需导入不依赖主解释器的隐式状态。
  • 任务足够粗,能覆盖解释器创建和序列化成本。
  • 异常、超时、取消和进程退出策略已经写进调用方。
  • 第三方原生扩展已经确认支持多解释器,或已选择进程池替代。

小结

用 InterpreterPoolExecutor 并行执行纯 Python 计算,核心是三个动作:使用 Python 3.14 以上版本,把任务函数写成可序列化、少依赖隐式状态的顶层函数,再用 Future 收集结果并处理异常。它通过多个隔离解释器提供独立 GIL,而不是让多个线程共享同一份可变内存。只要把数据边界和任务粒度一起设计,才有机会在实际 CPU 任务中获得值得维护的并行收益。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Python queue.ShutDown怎样让消费者感知队列关闭Python queue.ShutDown怎样让消费者感知队列关闭
上一篇
Python queue.ShutDown怎样让消费者感知队列关闭
下一篇
下一篇
暂无
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    887次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    883次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    968次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    952次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    780次使用