I'm attempting to parallelize a script I wrote. Each process needs to do a calculation and store the data to a specific part of an array (list of lists). Each process is calculating and storing its data alright, but I can't figure out how to get the data from the non-root processes to the root process so that it can print the data out to file. I created a minimum working example of my script---this one is designed to run on 2 cores only for simplicity:
from mpi4py import MPI
import pdb
import os
comm = MPI.COMM_WORLD
size = comm.Get_size()
rank = comm.Get_rank()
# Declare the array that will store all the temp results
temps = [[0 for x in xrange(5)] for x in xrange(4)]
# Loop over all directories
if rank==0:
counter = 0
for i in range(2):
for j in range(5):
temps[i][j] = counter
counter = counter + 1
else:
counter = 20
for i in range(2,4):
for j in range(5):
temps[i][j] = counter
counter = counter + 1
temps = comm.bcast(temps,root=0)
if rank==0:
print temps
I execute the script using:
mpiexec -n 2 python mne.py
When the case finishes, the output is:
[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
So you can see that the data sharing is not working as I want. Can someone please show me the correct way to get data back to the root process?
The code is working correctly, just not doing what you'd like.
This line
temps = comm.bcast(temps,root=0)
broadcasts processor 0's temps variable to all processors (including rank 0), which of course gives exactly the results above. You want to use gather (or allgather, if you want all of the processors to have the answer). That would look something more like this:
from mpi4py import MPI
import pdb
import os
comm = MPI.COMM_WORLD
size = comm.Get_size()
rank = comm.Get_rank()
assert size == 2
# Declare the array that will store all the temp results
temps = [[0 for x in xrange(5)] for x in xrange(4)]
# declare the array that holds the local results
locals =[[0 for x in xrange(5)] for x in xrange(2)]
# Loop over all directories
if rank==0:
counter = 0
for i in range(2):
for j in range(5):
locals[i][j] = counter
counter = counter + 1
else:
counter = 20
for i in range(2):
for j in range(5):
locals[i][j] = counter
counter = counter + 1
temps = comm.gather(locals,temps,root=0)
if rank==0:
print temps
If you really want to do the collection in-place, and you know (say) that all the real data is going to be larger than the zero you've initialized the data with, you can use a reduction operation, but that goes easier with numpy arrays:
from mpi4py import MPI
import numpy
comm = MPI.COMM_WORLD
size = comm.Get_size()
rank = comm.Get_rank()
assert size == 2
# Declare the array that will store all the temp results
temps = numpy.zeros((4,5))
# Loop over all directories
if rank==0:
counter = 0
for i in range(2):
for j in range(5):
temps[i,j] = counter
counter = counter + 1
else:
counter = 20
for i in range(2,4):
for j in range(5):
temps[i,j] = counter
counter = counter + 1
comm.Allreduce(MPI.IN_PLACE,temps,op=MPI.MAX)
if rank==0:
print temps
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With