Python:os.fork()如何工作?

tud*_*uya 20 python fork

我在python中学习多处理.我尝试了多处理,在读完多处理模块的源代码之后,我发现它使用了os.fork(),所以我写了一些代码来测试os.fok(),但是我被困了.我的代码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import time

for i in range(2):
    print '**********%d***********' % i
    pid = os.fork()
    print "Pid %d" % pid
Run Code Online (Sandbox Code Playgroud)

我认为每次打印都会执行两次,但执行三次.我无法理解这是如何工作的?我读过这个需要知道fork是如何工作的?
从这篇文章中说它也将被执行两次,所以我被困......

344*_*442 41

首先,删除该print '******...'行.它只会让每个人感到困惑.相反,让我们试试这段代码......

import os
import time

for i in range(2):
    print "I'm about to be a dad!"
    time.sleep(5)
    pid = os.fork()
    if pid == 0:
        print "I'm {}, a newborn that knows to write to the terminal!".format(os.getpid())
    else:
        print "I'm the dad of {}, and he knows to use the terminal!".format(pid)
        os.waitpid(pid)
Run Code Online (Sandbox Code Playgroud)

好的,首先,什么是"分叉"?Fork是现代和标准兼容的操作系统的一个特性(除了M $ Windows:操作系统的笑话几乎都是现代的和符合标准的)允许进程(又名:"程序",包括Python解释器) !)从字面上完全复制自己,有效地创建一个新的过程("程序"的另一个实例).一旦魔术完成,两个过程都是独立的.改变其中一个中的任何内容都不会影响另一个.

用于拼写这种黑暗和古老咒语的过程被称为父过程.这种对生命本身的憎恶的无灵魂结果被称为儿童过程.

对于所有人来说都是显而易见的,包括那些不是的人,你可以成为那些通过手段卖掉灵魂的精选程序员的一员os.fork().该功能执行分叉操作,因此导致第二个过程是凭空创建的.

现在,这个函数返回了什么,或者更重要的是,它甚至如何返回?如果你不想变得疯狂,不要去阅读Linux内核的/kernel/fork.c文件!一旦内核完成我们知道它必须做的事情,但我们不想接受它,os.fork()两个进程中返回!是的,甚至复制了调用堆栈!

那么,如果它们是精确的副本,父母和孩子之间的差异如何?简单.如果结果os.fork()为零,那么你就是在孩子身上工作.否则,您正在父项中工作,返回值是子项的PID(进程标识符).无论如何,孩子可以从中获得自己的PID os.getpid(),不是吗?

现在,考虑到这一点,以及在fork()循环内部进行混乱的事实,这就是发生的事情.让我们将原始流程称为"主"流程......

  • 师父:i = 0分成小孩 - #1-of-master
    • i = 1孩子 - #1-of-master:分叉为孩子 - #1-of-child-#1-of-master
    • 孩子 - #1-of-child-#1-of-master:for循环,退出
    • 孩子 - #1-of-master:for循环,退出
  • 师父:i = 1分成小孩 - #2-of-master
    • i = 1孩子 - #2-of-master:分叉为孩子 - #1-of-child-#2-of-master
    • 孩子 - #1-of-child-#2-of-master:for循环,退出
    • Child-#2-of-master:for循环,退出
  • 主人:for循环,退出

正如您所看到的,共有6个父/子打印来自4个独特的过程,产生6行输出,类似于......

我是12120的爸爸,他知道要使用终端!

我是12120,一个知道要写到终端的新生儿!

我是12121的爸爸,他知道要使用终端!

我是12121,一个知道要写到终端的新生儿!

我是12122的父亲,他知道要使用终端!

我是12122,一个知道要写到终端的新生儿!

但这只是武断的,它可能会输出这个......

我是12120,一个知道要写到终端的新生儿!

我是12120的爸爸,他知道要使用终端!

我是12121,一个知道要写到终端的新生儿!

我是12121的爸爸,他知道要使用终端!

我是12122,一个知道要写到终端的新生儿!

我是12122的父亲,他知道要使用终端!

或者其他任何东西.操作系统(和你的主板的时髦时钟)是唯一负责进程获取时间片的顺序的,所以如果你不喜欢内核如何组织你的进程,那么就要归咎于Torvalds(并期望在返回时没有自我推销) ;) .

我希望这对你有所启发!

  • 非常好的解释. (2认同)
  • 这可能是我在这个网站上读过的最有趣,最有洞察力的答案!竖起大拇指为感觉敲门!:d (2认同)

glg*_*lgl 26

要直接回答这个问题,os.fork()可以通过调用底层的OS函数来实现fork().

但你肯定对它的作用感兴趣.那么这会创建另一个过程,它将在与此完全相同的位置恢复.因此,在第一个循环运行中,你得到一个fork,之后你有两个进程,"原始的"(获取pid子进程的PID的值)和分叉的进程(获取pid0).

它们都打印它们的pid值并继续第二次循环运行,它们都打印出来.然后他们都分叉,留下4个进程,这些进程都打印各自的pid值.其中两个应该是0,其他两个应该是他们刚创建的孩子的PID.

将代码更改为

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import time

for i in range(2):
    print '**********%d***********' % i
    pid = os.fork()
    if pid == 0:
        # We are in the child process.
        print "%d (child) just was created by %d." % (os.getpid(), os.getppid())
    else:
        # We are in the parent process.
        print "%d (parent) just created %d." % (os.getpid(), pid)
Run Code Online (Sandbox Code Playgroud)

你会看到更好的结果:每个进程都会告诉你它自己的PID以及fork上发生了什么.