尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

为什么子进程总是拿不到数据?聊聊Python多进程里的“隔阂”

为什么子进程总是拿不到数据?聊聊Python多进程里的“隔阂”
📅 发布时间:2026/7/3 20:59:06

免费编程软件「python+pycharm」
链接:https://pan.quark.cn/s/48a86be2fdc0

一个让我在数据清洗项目上翻车的Bug

去年我接了一个数据清洗的活,需要处理100万行日志数据。每行数据要做格式校验、字段提取、类型转换,纯Python跑起来慢得让人抓狂。

我心想:Python多线程有GIL,那我用多进程总行了吧?每个核跑一个进程,4核机器至少提速3倍。

于是我写了这样的代码:

import multiprocessing as mp # 全局配置,所有子进程都要用 CONFIG = {"date_format": "%Y-%m-%d", "max_length": 100} def clean_line(line): # 用CONFIG里的配置清洗单行数据 # ... return cleaned if __name__ == "__main__": with mp.Pool(4) as pool: results = pool.map(clean_line, data)

看起来没问题吧?跑起来之后,诡异的事情发生了:配置在子进程里经常读不到,有时候读到的还是旧值。

我当时完全懵了——全局变量不是所有地方都能访问吗?为什么子进程就不行?

后来我才明白:多进程之间是“隔阂”的,每个进程有自己独立的记忆空间,你主进程里的变量,子进程根本看不见。


为什么子进程拿不到你的数据?

要理解这个问题,先记住一句话:进程是独立的。

当你用multiprocessing.Process或者Pool创建一个子进程时,Python会做这样几件事:

  1. 启动一个新的Python解释器(相当于重新打开了一个Python程序)

  2. 在新的解释器里,重新执行你的代码(包括导入模块、定义函数、执行全局代码)

  3. 子进程有自己的内存空间,和主进程完全隔开

所以你在主进程里定义的CONFIG、my_list、global_counter,子进程都看不见。不是Python不让它们共享,而是操作系统根本不允许一个进程随便读另一个进程的内存。

阿里云开发者社区的一篇文章里有一个很直观的例子:

from multiprocessing import Process num = 10 # 主进程的全局变量 def run(): global num num += 1 print(f"子进程里: {num}") if __name__ == "__main__": p = Process(target=run) p.start() p.join() print(f"主进程里: {num}")

运行结果:

子进程里: 11 主进程里: 10

看到了吗?子进程改了num,主进程里的num纹丝不动。子进程拿到的是num的一份拷贝,而不是引用。


子进程为什么总是“拿不到数据”?

真实项目里,“拿不到数据”通常表现为这几种情况:

情况1:全局变量在子进程里是“初始值”

就像前面的例子,你在主进程里修改了CONFIG,然后启动子进程,子进程看到的CONFIG可能是最初的值——因为子进程启动时重新执行了模块代码,用的是初始值。

情况2:Windows下更坑

在Windows系统上,multiprocessing启动子进程时会重新导入主模块。这意味着模块顶层所有的代码都会在子进程里再执行一遍。

如果模块顶层有耗时的初始化操作(比如加载大模型、连接数据库),每个子进程都会重复执行一遍,你的程序会慢到怀疑人生。

情况3:进程池(map)里修改不了列表

你可能会这样写:

results = [] # 想把结果收集到这里 def worker(x): results.append(x * 2) # 试图修改全局列表 with mp.Pool(4) as pool: pool.map(worker, range(10)) print(results) # 还是空的!

每个子进程修改的是自己那份results的拷贝,主进程的results从来没变过。


那怎么让子进程“拿到”数据?

好消息是,Python提供了好几种办法来打破这种“隔阂”。

方法1:通过参数传递(最推荐)

不要依赖全局变量,把要用的数据通过参数传进去:

def clean_line(line, config): # 用传进来的config,不用全局的 return cleaned if __name__ == "__main__": CONFIG = {...} with mp.Pool(4) as pool: # 把config作为参数传进去 results = pool.map(lambda x: clean_line(x, CONFIG), data)

这是最简单、最干净的方式。数据从一个地方流向另一个地方,没有隐式的全局依赖。

方法2:用multiprocessing.Queue传递数据

Queue是一个可以在多个进程之间安全传递数据的队列。

from multiprocessing import Process, Queue def worker(q): q.put("子进程处理完了") if __name__ == "__main__": q = Queue() p = Process(target=worker, args=(q,)) p.start() result = q.get() # 主进程收到子进程的消息 print(result)

Queue的原理是:一个进程把数据放进去,另一个进程取出来。数据被序列化后在进程间传递。

方法3:用Manager共享对象

如果你想让多个子进程共享一个列表或字典,可以用Manager:

from multiprocessing import Process, Manager def worker(shared_list): shared_list.append("来自子进程的数据") if __name__ == "__main__": manager = Manager() shared_list = manager.list(["主进程的数据"]) p = Process(target=worker, args=(shared_list,)) p.start() p.join() print(shared_list) # ['主进程的数据', '来自子进程的数据']

Manager的原理是:启动一个独立的“管理器进程”,所有对共享数据的操作都通过这个进程来协调。缺点是慢,因为每次读写都要走进程间通信。

方法4:用shared_memory共享内存(Python 3.8+)

如果数据量大且对性能有要求,可以用shared_memory模块:

from multiprocessing import shared_memory import numpy as np # 主进程创建共享内存 shm = shared_memory.SharedMemory(create=True, size=100) # 子进程通过名字连接到这块内存 shm_b = shared_memory.SharedMemory(name=shm.name)

这是最高效的方式,数据在内存中直接共享,不需要序列化和复制。


一张图理清楚

你想要做的事错误做法正确做法
子进程读主进程的配置用全局变量通过函数参数传递
子进程返回结果给主进程修改全局列表用Queue或返回值
多个子进程共享一个计数器用全局变量用Manager或Value
多个子进程共享超大数组用Manager列表用shared_memory

回到开头的Bug

我那个数据清洗项目最后怎么解决的?

我把CONFIG从全局变量改成了函数参数,每个子进程通过参数拿到配置。至于那些需要汇总的结果,我用Queue从子进程收集回来。

虽然代码多写了几行,但再也不会有“子进程拿不到数据”的烦恼了。

记住:多进程之间是“隔阂”的,别指望它们共享记忆。想要传递数据,要么递纸条(参数/Queue),要么用公共黑板(Manager/shared_memory)。

相关新闻

  • Qwen-Image-Edit-Rapid-AIO:技术架构驱动的极简AI图像编辑解决方案
  • 电话号码地理定位技术:从陌生来电识别到精准地图标记的完整解决方案
  • 今天不学就淘汰:2024新版《律师执业规范》AI条款深度解析,ChatGPT文书输出必须嵌入的6个法定标注项

最新新闻

  • 实战指南:5步精通MDUT多数据库利用工具的开发与定制
  • 如何解决Godot游戏性能瓶颈:C++扩展开发实战指南
  • 2024年Tomcat手动配置实战与优化指南
  • EasyGoAdmin 敏捷开发框架 v3.1.1 更新,多版本多组件助力开发效率提升!
  • BaiduPCS-Web:免费开源百度网盘下载加速终极指南
  • 终极免费方案:IDM激活脚本完全指南 - 永久冻结30天试用期

日新闻

  • JMeter接口测试实战:从核心元件到复杂场景构建
  • Java Applet版刽子手游戏源码:含完整项目结构、吊杆绘图与胜负逻辑
  • 使用Apache JMeter对RoadRunner PHP应用进行性能测试与调优指南

周新闻

  • Windows字体自定义终极方案:No!! MeiryoUI完全指南
  • Deepin Boot Maker:告别命令行,3分钟制作Linux启动盘的智能解决方案
  • Plain Craft Launcher 2:重新定义你的Minecraft游戏体验

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号