Ваш пример кода, кажется, имеет больше проблем, чем форма.Вы получаете желаемый результат только при удаче.Повторное выполнение даст разные результаты.Это потому, что +=
не является атомарной операцией.Несколько процессов могут читать одно и то же старое значение один за другим, прежде чем какой-либо из них обновит его, и они будут записывать одни и те же значения.Чтобы предотвратить такое поведение, вам придется дополнительно использовать Manager.Lock
.
К исходному вопросу о «хорошей форме».
ИМО было бы чище, чтобыглавная функция дочернего процесса foo_parallel
, явно передать global_dict
в обобщенную функцию add(var)
.Это будет форма внедрения зависимости и имеет некоторые преимущества.В вашем примере неисчерпывающе:
- позволяет изолированное тестирование
- увеличивает возможность повторного использования кода
упрощает отладку (обнаруживает недоступность управляемогообъект не должен быть отложен до тех пор, пока не будет вызван add
( fail fast )
меньше стандартного кода (например, блоки try-excepts для ресурсов, которые требуются нескольким функциям)
В качестве дополнительного примечания. Использование списочных представлений только для побочных эффектов считается «запахом кода». Если в результате вам не нужен список, просто используйтедля петли.
код:
import os
from multiprocessing import Process, Manager
def add(l):
l += [l[-1] + 1]
return l
def foo_parallel(global_dict, lock):
with lock:
l = global_dict['a']
global_dict['a'] = add(l)
print(os.getpid(), global_dict)
if __name__ == '__main__':
N_WORKERS = 5
with Manager() as manager:
lock = manager.Lock()
global_dict = manager.dict(a=[0])
pool = [Process(target=foo_parallel, args=(global_dict, lock))
for _ in range(N_WORKERS)]
for p in pool:
p.start()
for p in pool:
p.join()
print('result', global_dict)