多进程环境下无法修改DataFrame的问题求助
多进程下DataFrame无法修改的原因与解决办法
这个问题我碰到好多次了,本质是多进程的内存隔离机制在搞鬼,我给你拆解清楚:
为什么会出现这个问题?
当你用multiprocessing.Process创建子进程时,每个子进程都会拿到父进程数据的独立副本:
- 在Unix/Linux/macOS上是「写时复制」——子进程一开始共享父进程内存,但一旦修改数据,就会复制出自己的独立版本;
- 在Windows上则是直接完全复制父进程的所有内存数据。
所以你的myfunction里修改的data_attrib,其实是子进程自己的私有DataFrame副本,和父进程里的原DataFrame根本不是同一个对象。子进程运行结束后,它的内存会被回收,这些修改自然不会反映到父进程的DataFrame里。
可行的解决办法
方法1:用multiprocessing.Manager创建共享DataFrame
Manager可以帮你创建跨进程共享的对象,让所有子进程操作同一个DataFrame实例。不过要注意,共享对象会有锁开销,适合小数据量场景:
import multiprocessing import pandas as pd # 初始化你的DataFrame data_attrib = pd.DataFrame({'Id': [''] * len(data_attrib)}) def myfunction(i, shared_df): shared_df.at[i, 'Id'] = i print(shared_df.at[i, 'Id']) if __name__ == '__main__': # 用Manager创建可共享的DataFrame with multiprocessing.Manager() as manager: shared_data = manager.list([data_attrib])[0] processes = [] for i in data_attrib.index: pro = multiprocessing.Process(target=myfunction, args=(i, shared_data)) pro.start() processes.append(pro) # 等待所有进程结束 for process in processes: process.join() # 把共享对象同步回原DataFrame data_attrib = pd.DataFrame(shared_data) print(data_attrib['Id'])
方法2:进程池+结果合并(更高效)
这种方法不需要共享数据,而是让每个子进程处理后返回结果,最后在父进程里统一更新原DataFrame,性能更好,推荐用这个:
import multiprocessing import pandas as pd data_attrib = pd.DataFrame({'Id': [''] * len(data_attrib)}) def myfunction(i): # 返回索引和对应的值 return (i, i) if __name__ == '__main__': # 创建进程池(默认用CPU核心数) with multiprocessing.Pool() as pool: # 批量提交任务,获取所有结果 results = pool.map(myfunction, data_attrib.index) # 把结果更新到原DataFrame for idx, val in results: data_attrib.at[idx, 'Id'] = val print(data_attrib['Id'])
方法3:用pandas专用并行工具(简化代码)
如果你的任务是对DataFrame做逐行/逐列处理,可以用swifter库,它会自动判断用单进程还是多进程,代码更简洁:
import pandas as pd import swifter data_attrib = pd.DataFrame({'Id': [''] * len(data_attrib)}) def myfunction(row): row['Id'] = row.name # row.name就是当前行的索引i return row # 自动并行处理 data_attrib = data_attrib.swifter.apply(myfunction, axis=1) print(data_attrib['Id'])
额外注意事项
- Windows系统下,多进程代码必须放在
if __name__ == '__main__':代码块里,否则会触发无限创建子进程的bug,建议不管什么系统都加上; - 如果你的DataFrame数据量很小,多进程的启动开销反而会比单进程慢,没必要强行并行。
内容的提问来源于stack exchange,提问作者Giogioia
相关产品推荐
相关产品推荐

