Python多进程中全局/本地DataFrame的性能差异与内存复制疑问
Python多进程中全局/本地DataFrame的性能差异与内存复制疑问
嘿,咱们来一步步拆解你的两个疑问:
关于性能差异的原因
你发现用全局mydf的多进程快到离谱,而把DF作为本地参数传递的两种方式慢得让人崩溃,核心问题出在进程间的数据传递机制上:
- 你的Ubuntu是Linux系统,Python 3.11的
multiprocessing.Pool默认用fork方式创建子进程。当用全局变量时,fork出来的子进程会通过**写时复制(Copy-On-Write, COW)**机制共享父进程的内存空间——简单说,子进程一开始并没有真的复制那1GB的DF,只是“借用”父进程的内存页,只有当子进程修改这些内存页时才会真正复制一份。而你的_fun_global只是读取DF的前imax行,完全没修改原DF,所以根本没有复制开销,速度自然飞起。 - 但你把DF作为参数用
partial或starmap传递给子进程时,就必须把整个DF序列化成字节流(默认用pickle),再通过进程间通信(IPC)传给每个子进程,子进程还要反序列化还原成DF。1GB的DF做这套操作的开销是巨大的,这就是为什么这两种方式耗时近90秒,而全局变量方式只花了0.1秒。
关于系统监视器的内存显示疑问
Ubuntu系统监视器显示每个子进程占1.2GB内存,其实是名义内存占用,不是实际消耗的物理内存:
- 因为
fork的子进程共享父进程的内存页,系统监视器会把这些共享内存算到每个进程的“占用”里,所以看起来每个进程都占了和父进程差不多的内存,但实际物理内存并没有被重复占用——只有当某个子进程修改了共享的内存页(比如修改DF内容),才会触发COW机制,复制出属于自己的内存页,这时候才会真正消耗额外的物理内存。 - 这就是为什么所有进程的内存占用加起来会超过你的128GB系统内存,实际物理内存的总消耗远没有这么多,大部分是共享的。
最后补个小验证:你如果打开sleep(10)观察内存,其实这时候子进程只是读取DF,没有修改,所以实际物理内存根本没被复制,只是系统监视器的显示方式让你产生了“每个进程都占了1.2GB”的错觉~
备注:内容来源于stack exchange,提问作者M B
相关产品推荐
相关产品推荐

