Неожиданное поведение с многопроцессорным пулом

#python #multiprocessing

#python #многопроцессорная обработка

Вопрос:

В приведенном ниже коде я ожидал, что результат будет равен 2, поскольку я изменяю значение config перед назначением функции пулу для многопроцессорной обработки, но вместо этого я получаю 5. Я уверен, что для этого есть веская причина, но не уверен, как это объяснить.

 from multiprocessing import Pool 
config = 5

class Test:

  def __init__(self):
    print("This is init")

  @classmethod
  def testPrint(cls, data):
    print(config)
    print("This is testPrint")
    return config

if __name__ == "__main__" :
  pool = Pool()
  config = 2
  output = pool.map(Test.testPrint, range(10))
  print(output)
  

Вывод

 5
This is testPrint
5
This is testPrint
5
This is testPrint
5
This is testPrint
5
This is testPrint
5
This is testPrint
5
This is testPrint
5
This is testPrint
5
This is testPrint
5
This is testPrint
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
  

Комментарии:

1. Я не знаю точно, что здесь происходит, но мы в некоторой степени используем многопроцессорную обработку, и мы научились избегать глобальных переменных. В какой-то момент создается копия среды с помощью травления, потому что у вас нет среды с общей памятью. Точно, что происходит с этим конкретным значением, я не могу сказать. Что я добавлю, так это предложить то, что мы узнали … передавайте все ваши общие значения очень явно, как в подпроцессах, так и особенно из них.

2. Похоже, что ответ @tdelaney идет по тому же пути, но с более подробной информацией. Все хорошо.

3. @Steve я ожидал, что запись общих значений в подпроцессах будет испорчена, но не чтение. Сегодня узнал кое-что новое.

Ответ №1:

Новые процессы создаются при создании пула. После этого изменения, внесенные в родительское пространство памяти, за исключением материалов, которые передаются в функции пула, например .map , не видны подпроцессу. Системы разветвления, такие как Linux, создают представления копирования при записи в родительское пространство памяти, и эта запись приводит к созданию уникального блока памяти для родительского, не видимого подпроцессом. Порождающие системы повторно импортируют модули (устанавливая глобальные переменные), а затем пытаются определить / отменить состояние для подпроцессов. В обоих случаях это выполняется до Pool того, как инициализация класса вернется в вашу программу.

Комментарии:

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