If your startmethod
is spawn
or forkserver
, then A
is not a shared object in the first place. And if you're on Windows, spawn
is the default, and only choice.
If your startmethod
is fork
, then A
may be a shared object—but if it is, it isn't actually safe to mutate it without any locks.
As explained in Sharing state between processes, you should try as hard as possible to not need shared objects—it's kind of the whole point of multiprocessing that the processes are isolated from each other—but if you really do need them, you have to do something a bit more complicated.
The first option is using shared memory. In this case, you're using your list as a fixed-sized array of small ints, which you can simulate with an Array('i', [1, 2])
, which you can use exactly as in the example in the docs. For more complicated cases, you often need to add a Lock
or other synchronization mechanism to protect the shared memory. This is pretty efficient and simple, but it only works when your shared data is something that can be mapped to low-level types like this.
The second option is using a Manager.list([1, 2])
, which you can use exactly as in the very next example in the docs. This is a lot less efficient—it works by creating a queue and passing messages back and forth that tell the main process to do the work whenever you want to access or mutate the list—but it has the advantage of being dead simple to use.
But again, it's usually better to not do either of these things, and instead rewrite your code to not need shared data in the first place. Usually this means returning more data from the pool tasks, and then having the main process assemble the returned values in some way. Of course this is tricky if, e.g., other tasks inherently need to see the mutated values. (In such cases, you'd often have to build 80% of what Manager
is doing, at which point you might as well just use Manager
…). But in your toy example, that isn't the case. (And, in fact, when you think that's unavoidably necessary, it often means you haven't thought through how nondeterminism is going to affect your algorithm, and it wouldn't have worked anyway…)
Here's an example of how you could do this with your toy problem:
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)