关于父子进程,先从操作系统说起。
- 操作系统中,每个进程都占用不同的内存空间,也就是物理内存空间。所以说,不同进程的数据都是隔离的。不管进程间的关系如何。
- 之所以,父子进程间数据共享隔离,容易让人疑惑,是因为父进程创建子进程时,会把父进程的内容完全copy一份,进程的虚拟地址完全相同(注意两个虚拟地址相同,但它们分别对应的物理地址完全不同)。 另外,linux系统在copy子进程时,使用copy-on-write技术,只有在修改数据时,才真正创建自己的物理空间,并copy对应的变量到自己的物理空间。也就是说,刚创建完成子进程且修改数据前,子进程和父进程占用相同的虚拟空间和物理空间。
- 进程间的数据相互隔离,要想共享,必须通过中间媒介实现。常用的技术手段,就是管道、文件、队列、kafka等第三方消息队列等。
python属于操作系统的上层应用,也要遵从相同的规则,即子进程从父进程创建它的位置出开始执行,并完全copy父进程内存空间。
但是,python程序的运行解释性特征,子进程在运行时,每个文件中的全局变量、全局语句,都会先执行一次。因此,主进程创建子进程前对全局变量的修改对子进程无效,python编程中特别注意。分别用python和c,来验证:
# -*- coding: utf-8 -*-
import multiprocessing
import os
print(f'pid={os.getpid()},context printing')
a = 0
def run():
print(f'''child process,pid = {os.getpid()},a = {a}''')
if __name__ == '__main__':
a = 10
print(f'''main process,pid = {os.getpid()},a = {a}''')
p = multiprocessing.Process(target=run)
p.start()
p.join()
print(f'''main process,pid = {os.getpid()},a = {a}''')
输出结果
pid=7378,context printing,a=0
main process,pid = 7378,a = 10
pid=7380,context printing,a=0
child process,pid = 7380,a = 0
main process,pid = 7378,a = 10
相同算法,C语言重写
#include <stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
int a = 10;
void f(int y){
a += y;
}
int main(void)
{
printf("process id %d, %d \n",getpid(),a);
pid_t pid;
a = 2;
pid = fork();
if (pid > 0)
{
f(2);
printf("parent process id %d,%d \n",getpid(),a);
}
else if (pid == 0)
{
f(3);
printf("child process id %d,%d \n",getpid(),a);
}else{
perror("fork error");
}
}
运行结果:
process id 26889, 10
parent process id 26889,4
child process id 26890,5
参考:博文