Разница в поведении между os.fork и multiprocessing.Process

У меня есть этот код:

import os

pid = os.fork()

if pid == 0:
    os.environ['HOME'] = "rep1"
    external_function()
else:
    os.environ['HOME'] = "rep2"
    external_function()

и этот код:

from multiprocessing import Process, Pipe

def f(conn):
    os.environ['HOME'] = "rep1"
    external_function()
    conn.send(some_data)
    conn.close()

if __name__ == '__main__':
    os.environ['HOME'] = "rep2"
    external_function()
    parent_conn, child_conn = Pipe()
    p = Process(target=f, args=(child_conn,))
    p.start()
    print parent_conn.recv()
    p.join()

external_function инициализирует внешние программы, создавая необходимые подкаталоги в каталоге, указанном в переменной окружения HOME. Эта функция работает только один раз в каждом процессе.

В первом примере, в котором используется os.fork(), каталоги создаются, как и ожидалось. Но во втором примере, в котором используется multiprocessing, создаются только каталоги в rep2.

Почему во втором примере каталоги не создаются как в rep1, так и в rep2?


person Hunsu    schedule 04.06.2014    source источник
comment
Я не могу воспроизвести проблему, которую вы видите. Я написал external_function вот так: def external_function(): print os.environ['HOME'] и обнаружил, что пример multiprocessing вывел именно то, что я ожидал; 'rep1', 'rep2' и строка, которую я отправил обратно из conn.send, были напечатаны.   -  person dano    schedule 04.06.2014
comment
Думаю, вы найдете ответ здесь.   -  person    schedule 04.06.2014
comment
Я выполняю функцию getInstalledPackages из github.com/vle-forge. /pyvle/blob/master/src/pyvle.py.   -  person Hunsu    schedule 04.06.2014
comment
@andi Вот что я подозревал. Если вы напишете ответ, я приму его.   -  person Hunsu    schedule 04.06.2014
comment
Я сделаю это. Дай мне минуту.   -  person    schedule 04.06.2014


Ответы (2)


Ответ, который вы ищете, подробно описан здесь. Также есть объяснение различий между разными ОС.

Одна большая проблема заключается в том, что системный вызов fork не существует в Windows. Поэтому при работе с ОС Windows вы не можете использовать этот метод. multiprocessing — это интерфейс более высокого уровня для выполнения части запущенной в данный момент программы. Следовательно, он, как и разветвление, создает копию текущего состояния вашего процесса. Другими словами, он позаботится о разветвлении вашей программы для вас.

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

person Community    schedule 04.06.2014
comment
Пожалуйста, если у кого-то еще есть тот же вопрос, что и у пользователя выше, этот ответ не дает ничего, кроме еще одной ссылки для спуска. Если бы вы могли поместить соответствующую информацию в свой ответ, как того требуют принципы сообщества, я удалю свой отрицательный голос. - person Poik; 04.06.2014
comment
Надеюсь, это то, о чем вы просите. В противном случае дайте мне знать. Спасибо за вашу критику. - person ; 04.06.2014
comment
На самом деле он не создает копию текущего процесса в Windows. В противном случае все предупреждения, перечисленные здесь, не будут проблемой. Смотрите мой ответ для более подробной информации. - person Poik; 04.06.2014
comment
«заботится о разветвлении для вас» ... что, если моя программа разветвляется внутри блокировки. Ожидается ли тупик? Если между мной и разветвлением есть слой абстракции, важны детали. - person user48956; 16.04.2018

Чтобы ответить на ваш вопрос напрямую, должен быть какой-то побочный эффект external_process, который делает так, что когда код запускается последовательно, вы получаете разные результаты, чем если бы вы запускали их одновременно. Это связано с тем, как вы настраиваете свой код, а также с отсутствием различий между os.fork и multiprocessing.Process в системах, которые поддерживают os.fork.


Единственная реальная разница между os.fork и multiprocessing.Process заключается в переносимости и накладных расходах библиотеки, поскольку os.fork не поддерживается в Windows, а multiprocessing включена, чтобы заставить multiprocessing.Process работать. Это связано с тем, что os.fork вызывается multiprocessing.Process, поскольку этот ответ поддерживает.

Таким образом, важным отличием является то, что os.fork копирует все в текущем процессе, используя разветвление Unix, что означает, что во время разветвления оба процесса одинаковы с различиями PID. В Windows это эмулируется повторным запуском всего кода установки перед if __name__ == '__main__':, что примерно аналогично созданию подпроцесса с использованием библиотеки subprocess.

Для вас фрагменты кода, которые вы предоставляете, делают совершенно разные вещи, описанные выше, потому что вы вызываете external_function в main, прежде чем открывать новый процесс во втором фрагменте кода, заставляя два процесса выполняться последовательно, но в разных процессах. Кроме того, канал не нужен, так как он не эмулирует функциональность из первого кода.

В Unix фрагменты кода:

import os

pid = os.fork()

if pid == 0:
    os.environ['HOME'] = "rep1"
    external_function()
else:
    os.environ['HOME'] = "rep2"
    external_function()

и:

import os
from multiprocessing import Process

def f():
    os.environ['HOME'] = "rep1"
    external_function()

if __name__ == '__main__':
    p = Process(target=f)
    p.start()
    os.environ['HOME'] = "rep2"
    external_function()
    p.join()

должен делать то же самое, но с небольшими дополнительными накладными расходами из-за прилагаемой библиотеки многопроцессорности.


Без дополнительной информации мы не можем понять, в чем проблема. Если вы можете предоставить код, демонстрирующий проблему, это поможет нам вам помочь.

person Poik    schedule 04.06.2014
comment
Пример Dano отличается от того, что делает моя функция. - person Hunsu; 04.06.2014
comment
Но его комментарий по-прежнему актуален, мы не можем воспроизвести поведение, с которым вы сталкиваетесь, без вашего участия. - person Poik; 04.06.2014
comment
Если вы хотите воспроизвести поведение, с которым я столкнулся, вы должны установить кучу пакетов. - person Hunsu; 04.06.2014
comment
Если правка Дано верна, то мы не можем ответить на ваш вопрос, по крайней мере, не получив названия пакетов. - person Poik; 04.06.2014
comment
Вы можете ответить на мой, если вы знаете разницу между ними. - person Hunsu; 04.06.2014
comment
Здесь больше проблем, чем различий в библиотеках. Могут быть побочные эффекты external_function, которые мы не можем объяснить, и это единственное известное мне объяснение описанного вами поведения. Кроме того, как говорится в моем ответе и ответе Энди, различия заключаются в том, что библиотека multiprocessing обертывает os.fork. - person Poik; 04.06.2014