小知识,大挑战!本文正在参与「程序员必备小知识」创作活动
posix 的进程机制是一个很神奇的东西,如果我们先学习过java之类的并发机制会发现这个是有点不太合乎我们的习惯的。
在Java中我们使用线程的时候是这样的,假设我们有一段想要同时执行的代码,我们应该直接让把程序传递给线程让他执行(给线程一个run方法)。按照这个推断,那么我们想要通过进程来实现并发,应该也是通过给一段程序(或者一个可执行程序)让它运行。
但是事与愿违,posix的进程是并不和我们想的一样,它的执行类似一个树型结构,树的分叉由一个名叫fork的函数实现。我们以python中的os.fork 为例子。
x =[1]
if os.fork() == 0:
x.append(2)
print(x,os.getpid(),os.getppid())
else:
x.append(3)
print(x,os.getpid(),os.getppid())
# 我的电脑运行结果
# [1, 3] 107891 228818
# [1, 2] 107892 107891
为什么说他是叉子呢?因为在fork函数之后,会变成两个进程,两个进程运行的是同样的代码,而且都处于fork函数处,然后原来的进程得到的函数返回值是创建的子进程的进程号,而子进程得到的返回值则是0。 说他们运行的是相同的代码,是因为在系统会把程序的资源拷贝一份交给子进程。
所以在fork之前的变量之类的,子进程会有和原来的进程一样的数据。 而在上面我们使用了一个if分支判断自己是不是新的被创建的进程。
两个进程必然会得到不一样的值,这样他们就会执行不同的分支。
这个时候,它的行为表现得就和分叉这个形状很相似了。
在这上面的例子中,我们都对x进行了append操作,但没有使用相同的值,从输出来看,可以发现x确实被复制了一份,两者在fork之后的操作实际上已经不再同一个进程了。
从后面的进程id输出也可以看到,输出2的进程父进程是为107891。 如果有必要做类似java的操作我们也可以把分支的运行改成函数效果
def f1():
pass
def f2():
pass
if os.fork() == 0:
f1()
else:
f2()
这样我们勉强可以做到类似Java多线程的方式使用了。