Как создать дочерний процесс, использующий многопроцессорность в Python2.7.10, без дочернего совместного использования ресурсов с родительским? - PullRequest
3 голосов
/ 14 марта 2019

Мы пытаемся переместить нашу кодовую базу python 2.7.10 из Windows в Linux.Недавно мы обнаружили, что многопроцессорная библиотека в Python 2.7 ведет себя по-разному в Windows и Linux.Мы нашли много статей, таких как эта , описывающих проблему, однако мы не можем найти онлайн решение для Python 2.7. Это исправление для этой проблемы в Python 3.4, однако мы не можем выполнить обновление до Python 3.4.Есть ли способ использовать многопроцессорность в Python 2.7 в Linux без совместного использования дочерней и родительской памяти?Мы также можем использовать руководство по изменению кода forking.py в python 2.7, чтобы гарантировать, что дочерний и родительский процессы не разделяют память и не выполняют копирование при записи.Спасибо!

Ответы [ 2 ]

1 голос
/ 15 марта 2019

Возможное решение - использовать loky, библиотеку, которая обеспечивает реализацию Process с fork-exec в python2.7.* Start-метод fork-exec ведет себя так же, как spawn, со свежим интерпретатором во вновь порожденном процессе.Библиотека в основном предназначена для обеспечения concurrent.futures API, но вы можете использовать mp = loky.backend.get_context() для получения того же API, что и multiprocessing.

from loky.backend import get_context
import multiprocessing as mp


def child_without_os():
    print("Hello from {}".format(os.getpid()))


def child_with_os():
    import os
    print("Hello from {}".format(os.getpid()))


if __name__ == "__main__":
    import argparse
    parser = argparse.ArgumentParser('Test loky backend')
    parser.add_argument('--use-fork', action="store_true",
                        help="Use start_method='fork' instead of 'loky'")
    parser.add_argument('--with-os', action="store_true",
                        help='Import os module in the child interpreter')
    args = parser.parse_args()

    # Only import os in the main module, this should fail if the interpreter is
    # not shared
    import os
    print("Main is {}".format(os.getpid()))
    if args.use_fork:
        ctx = mp
        print("Using fork context")
    else:
        ctx = get_context('loky_init_main')
        print("Using loky context")

    if args.with_os:
        target = child_with_os
    else:
        target = child_without_os

    p = ctx.Process(target=target)
    p.start()
    p.join()

Это дает

# Use the default context, the child process has a copy-on-write interpreter
# state and can use the os module.
$ python2 test.py --use-fork
Main is 14630
Using fork context
Hello from 14633


# Use the loky context, the child process has a fresh interpreter
# state and need to import the os module.
$ python2 test.py
Main is 14661
Using loky context
Process LokyInitMainProcess-1:
Traceback (most recent call last):
  File "/usr/lib/python2.7/multiprocessing/process.py", line 267, in _bootstrap
    self.run()
  File "/usr/lib/python2.7/multiprocessing/process.py", line 114, in run
    self._target(*self._args, **self._kwargs)
  File "/home/tom/Work/prog/loky/test.py", line 6, in child_without_os
    print("Hello from {}".format(os.getpid()))
NameError: global name 'os' is not defined


# Now using the correct child function which import the os module
$ python2 test.py --with-os
Main is 14700
Using loky context
Hello from 14705

(ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я один из сопровождающих loky).

0 голосов
/ 14 марта 2019

Как вы, без сомнения, знаете, патчи в трекере ошибок CPython не применяются чисто к версии многопроцессорной обработки Python 2.7, и патчи включают некоторые дополнительные функции для semaphore.c, так что семафоры очищаются правильнопотом.

Я думаю, что вам лучше всего было бы сделать бэкпорт для модуля многопроцессорной обработки из Python 3. Скопируйте код Python, переименуйте его на processing, найдите недостающие функции C и обойдите их (например, очистите).ваши собственные семафоры или не используйте их).Несмотря на то, что библиотека большая, портировать можно только те функции, которые вы используете.Если вы сможете опубликовать бэкпорт, я уверен, что многие люди заинтересуются этим проектом.

В зависимости от того, насколько сильно вы полагаетесь на многопроцессорность, другим вариантом будет просто запустить больше Pythons, запустив * 1007.* с модулем subprocess.

...