Если ваш startmethod
равен spawn
или forkserver
, то A
не является общим объектом в первую очередь.И если вы в Windows, spawn
является значением по умолчанию и единственным выбором.
Если ваш startmethod
равен fork
, тогда A
может быть общим объектом, но если это так,на самом деле не безопасно изменять его без каких-либо блокировок.
Как объяснено в Совместное использование состояния между процессами , вы должны стараться изо всех сил, чтобы не нуждаться в общих объектах - это своего родаВесь смысл многопроцессорности в том, что процессы изолированы друг от друга, но если они вам действительно нужны, вам нужно сделать что-то более сложное.
Первый вариант - использование общей памяти.В этом случае вы используете свой список в виде массива небольших целых с фиксированным размером, который вы можете смоделировать с помощью Array('i', [1, 2])
, который вы можете использовать точно так же, как в примере в документации.В более сложных случаях часто требуется добавить Lock
или другой механизм синхронизации для защиты общей памяти.Это довольно эффективно и просто, но работает только тогда, когда ваши общие данные могут быть сопоставлены с низкоуровневыми типами, подобными этому.
Второй вариант - использование Manager.list([1, 2])
, которое вы можете использовать точнокак в следующем примере в документации.Это гораздо менее эффективно - оно работает, создавая очередь и передавая сообщения туда и обратно, которые сообщают основному процессу, что нужно выполнять работу всякий раз, когда вы хотите получить доступ к списку или изменить его, - но его преимущество в том, что он прост в использовании.
Но, опять же, обычно лучше не делать ни одну из этих вещей, а вместо этого переписать свой код, чтобы не нуждаться в общих данных в первую очередь.Обычно это означает, что нужно возвращать больше данных из задач пула, а затем заставить основной процесс каким-либо образом собрать возвращаемые значения.Конечно, это сложно, если, например, другие задачи по своей сути должны видеть измененные значения.(В таких случаях вам часто приходится собирать 80% того, что делает Manager
, и в этот момент вы можете просто использовать Manager
…).Но в вашем игрушечном примере это не так.(И, на самом деле, когда вы думаете , что неизбежно необходимо, это часто означает, что вы не продумали, как недетерминизм повлияет на ваш алгоритм, и все равно не сработало бы ...)
Вот пример того, как вы можете сделать это с вашей игрушкой:
import multiprocessing
def square(i, aval):
# actual return value, i, and value to set A[i] to
return i*i, i, 2+aval
A = [1, 2]
# pass each A[i] into the function
for result, i, aval in multiprocessing.Pool().starmap(square, zip([0, 1], A)):
# get the new A[i] out of the function and store it
A[i] = aval
print(A)