Python: Как работает os.fork()?

Я учусь мульти обработки в Python. Я попробовал многопроцессорную работу, и после того, как я прочитал исходный код многопроцессорного модуля, я обнаружил, что он использует os.fork(), поэтому я пишу некоторый код для тестирования os.fork(), но я застрял. Мой код выглядит следующим образом:

#!/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

Я думаю, что каждый отпечаток будет выполнен два раза, но они будут выполнены три раза. Я не могу понять, как это работает? Я прочитал это Нужно знать, как работает форк?
Из того, что говорится в этой статье, он также будет выполнен дважды, поэтому я так застрял...

Ответ 1

Чтобы ответить на вопрос напрямую, os.fork() работает, вызывая базовую функцию ОС fork().

Но вы, безусловно, заинтересованы в том, что это делает. Ну, это создает другой процесс, который возобновится точно в том же месте, что и этот. Таким образом, при первом запуске цикла вы получаете форк, после которого у вас есть два процесса: "оригинальный" (который получает значение pid для PID дочернего процесса) и разветвленный (который получает значение pid равное 0).,

Они оба печатают свои значения 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)

Вы лучше увидите, что происходит: каждый процесс сообщит вам свой PID и то, что произошло на развилке.

Ответ 2

Прежде всего, удалите эту строку 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)

Хорошо, во-первых, что такое "вилка"? Fork - это особенность современных и совместимых со стандартами операционных систем (за исключением M $ Windows: эта шутка операционной системы почти полностью соответствует современным требованиям и стандартам), которая допускает процесс (он же "программа") и включает в себя интерпретатор Python !) буквально сделать точную копию себя, эффективно создавая новый процесс (еще один экземпляр "программы"). Как только это волшебство сделано, оба процесса становятся независимыми. Изменение чего-либо в одном из них не влияет на другое.

Процесс, ответственный за написание этого темного и древнего заклинания, известен как родительский процесс. Бездушный результат этой безнравственной мерзости к самой жизни известен как детский процесс.

Как должно быть очевидно для всех, включая тех, для кого это не так, вы можете стать членом этой избранной группы программистов, которые продали свою душу с помощью os.fork(). Эта функция выполняет операцию разветвления и, таким образом, приводит к созданию второго процесса из воздуха.

Теперь, что возвращает эта функция, или, что более важно, как она вообще возвращает? Если вы не хотите сходить с ума, , пожалуйста,, не идите и не читайте файл ядра Linux /kernel/fork.c! Как только ядро делает то, что мы знаем, оно должно сделать, но мы не хотим принимать это, os.fork() возвращается в двух процессах! Да, даже стек вызовов скопирован!

Итак, если они являются точными копиями, как различить родителя и ребенка? Просто. Если результат os.fork() равен нулю, значит, вы работаете с ребенком. В противном случае вы работаете в родительском элементе, а возвращаемое значение - это PID (Process IDentifier) дочернего элемента. В любом случае, ребенок может получить свой собственный PID из os.getpid(), нет?

Теперь, принимая это во внимание, и тот факт, что выполнение fork() внутри цикла является рецептом для беспорядка, вот что происходит. Позвольте назвать оригинальный процесс "основным" процессом...

  • Мастер: i = 0, разветвляется на child- # 1-of-master
    • child- # 1-of-master: i = 1 разветвляется на child- # 1-of-child- # 1-of-master
    • child- # 1-of- child- # 1-of-master: for зацикливание, выход
    • child- # 1-of-master: for зацикливание, выход
  • Мастер: i = 1, разветвляется на child- # 2-of-master
    • child- # 2-of-master: i = 1 разветвляется на child- # 1-of-child- # 2-of-master
    • child- # 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, и он знает, как использовать терминал!

Или что-нибудь кроме этого. ОС (и часы вашей материнской платы в стиле фанк) несут полную ответственность за порядок, в котором процессы получают временные интервалы, поэтому возложите вину на на Торвальдса (и не ожидайте самообмана, когда вернетесь), если вам не нравится, как ядру удается организовать ваши процессы;).

Я надеюсь, что это пролило некоторый свет на вас!