Многопроцессорная обработка Python не очень хорошо работает с threading.local? - PullRequest
10 голосов
/ 02 сентября 2011

У меня есть два процесса (см. Пример кода), каждый из которых пытается получить доступ к объекту threading.local. Я ожидаю, что приведенный ниже код будет печатать «a» и «b» (в любом порядке). Вместо этого я получаю «а» и «а». Как я могу элегантно и надежно сбросить объект threading.local при запуске совершенно новых процессов?

import threading
import multiprocessing
l = threading.local()
l.x = 'a'
def f():
    print getattr(l, 'x', 'b')
multiprocessing.Process(target=f).start()
f()

edit: Для справки, когда я использую многопоточность. Thread вместо многопроцессорной обработки. Процесс работает как положено.

Ответы [ 3 ]

9 голосов
/ 02 сентября 2011

Обе упомянутые вами операционные системы основаны на Unix / Linux и, следовательно, реализуют один и тот же fork() ing API. A fork() полностью дублирует объект процесса вместе с его памятью, загруженным кодом, дескрипторами открытых файлов и потоками. Более того, новый процесс обычно использует один и тот же объект процесса в ядре до первой операции записи в память. В основном это означает, что локальные структуры данных также копируются в новый процесс вместе с локальными переменными потока. Таким образом, у вас все еще есть те же структуры данных, и l.x все еще определено.

Чтобы сбросить структуры данных для нового процесса, я бы порекомендовал функции запуска процесса сначала вызвать некоторый метод очистки. Например, вы можете сохранить pid родительского процесса с помощью process_id = os.getpid() и использовать

if process_id != os.getpid(): 
   clear_local_data()

В основной функции дочернего процесса.

3 голосов
/ 02 сентября 2011

Поскольку threading.local выполняет трюки для потоков, а не для процессов, как четко описано в его документации :

Значения экземпляра будут разными для отдельных потоков.

Ничего о процессах.

И цитата из многопроцессорной обработки doc :

Примечание

многопроцессорная обработка не содержитаналоги threading.active_count (), threading.enumerate (), threading.settrace (), threading.setprofile (), threading.Timer или threading.local .

0 голосов
/ 20 октября 2017

В Pypi теперь есть библиотека multiprocessing-utils ( github ) с многопроцессорной версией threading.local(), которая может быть установлена ​​в pip.

Он работает, оборачивая стандарт threading.local() и проверяя, что PID не изменился с момента его последнего использования (согласно ответу здесь от @immortal).

Используйте его точно так же, как threading.local():

l = multiprocessing_utils.local()
l.x = 'a'
def f():
    print getattr(l, 'x', 'b')
f()                                        # prints "a"
threading.Thread(target=f).start()         # prints "b"
multiprocessing.Process(target=f).start()  # prints "b"

Полное раскрытие: я только что создал этот модуль

...