You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python os.fork()多进程操作同一资源的三类技术疑问

关于Python中os.fork()进程的内存疑惑解答

先看你提供的测试代码:

import os
a=[]
pid=os.fork()
if(pid!=0):
    a.append(1)
    print("Original: ", end='')
    print(a,id(a))
else:
    a.append(2)
    print("Child: ", end='')
    print(a,id(a))

执行后输出:

Original: [1] 139725666412296
Child: [2] 139725666412296

接下来逐个解答你的疑问:

1. 为何父进程与子进程的资源ID(即列表a的id)相同?

这其实是个常见的误解——Python里的id()返回的是对象在进程虚拟地址空间中的内存地址,而非物理内存地址。

当你调用os.fork()时,内核会为子进程创建一个几乎完全复制的地址空间,但此时并不会真的把父进程的所有内存都拷贝一份(太浪费资源了),而是采用**写时复制(Copy-On-Write, COW)**机制:父子进程共享同一份物理内存页,直到其中一方尝试修改某个内存页。

在你的代码里,a=[]是在fork之前创建的,此时父子进程的虚拟地址空间里,列表a对应的虚拟地址完全一致,所以id(a)返回的值看起来相同,但这个值只在单个进程内有唯一性,跨进程是没有意义的。

2. 若二者共享同一ID,子进程向列表a追加元素2后,为何输出的列表不是[1,2]?

这正是写时复制机制在起作用:

  • fork之后,父子进程共享列表a所在的物理内存页,此时两个进程看到的a都是空列表。
  • 父进程执行a.append(1)时,需要修改内存页内容,内核会立刻把这个页复制一份给父进程,父进程修改的是自己的副本,所以父进程的a变成了[1]。
  • 子进程执行a.append(2)时,同样触发写时复制,内核会把原始的共享页(此时还是空的,因为父进程已经复制了自己的独立副本)复制一份给子进程,子进程修改自己的副本,所以子进程的a变成了[2]。

说白了,父子进程的a从修改操作开始就变成了完全独立的两个对象,只是它们的虚拟地址(即id()返回值)碰巧相同而已,互相的修改完全不会影响对方。

3. 在Jupyter Notebook的新代码块中打印变量a,结果为[1]。若父进程先执行、子进程后执行,为何变量a的内容不是[1,2]?

因为Jupyter的代码块始终运行在父进程中,子进程是一个完全独立的进程,它的内存空间和父进程彻底隔离。

子进程对a的修改只发生在自己的地址空间里,父进程根本感知不到。当你在新代码块打印a时,访问的是父进程里的那个a——也就是父进程之前追加了1的版本,自然就是[1]。

子进程运行结束后,它的所有内存资源都会被系统回收,不会对父进程的任何变量造成影响。

内容的提问来源于stack exchange,提问作者o_yeah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 20:42:57