В многопроцессорной документации (под multiprocessing.Value
) об этом совершенно ясно сказано:
Операции типа +=
, которые включают чтение и запись, не являются атомами c , Так, например, если вы хотите атомарно увеличить общее значение, недостаточно просто сделать counter.value += 1
.
Короче говоря, вам нужно захватить блокировку, чтобы иметь возможность сделать это.
Вы можете сделать это с помощью:
def add_to_value(addend, value, lock):
with lock:
value.value += addend
if __name__ == '__main__':
with multiprocessing.Manager() as manager:
lock = manager.Lock()
value = manager.Value(float, 0.0)
with multiprocessing.Pool(2) as pool:
pool.starmap(add_to_value,
[(float(i), value, lock) for i in range(100)])
print(value.value)
Это будет правильно выводить 4950.0.
Но учтите, что этот подход будет довольно дорогим из-за необходимости блокировки. Скорее всего, это займет больше времени, чтобы завершить sh, чем если бы у вас был один процесс, выполняющий операцию.
ПРИМЕЧАНИЕ: Я также добавляю if __name__ == '__main__':
guard, который на самом деле требуется при использовании метода запуска, отличного от fork . По умолчанию для ОС Windows и Ma c установлено spawn , поэтому действительно необходимо сделать этот код переносимым на любую из этих платформ. Методы запуска spawn и forkserver также доступны в Linux / Unix, поэтому в некоторых ситуациях это также необходимо.
Многопроцессорная обработка будет более эффективной, если вы Вы можете разгрузить работу для работников, которую они могут выполнить самостоятельно, например, рассчитать частичные суммы и затем сложить их вместе в основном процессе. Если возможно, подумайте над тем, чтобы переосмыслить свой подход к этой модели.