4

I wish to generate a periodic Perlin noise on a regular grid. I need to generate several maps, and the grid are quite large, so I wanted to use multiprocessing, to generate one map per core.

The maps are to be plotted on a figure, and put one after the other on a single binary dat file. The maps would be stored in a single numpy array, of size number of maps* number of nodes, so a slice would be a map, and I could hence access different zones of the array at the same time without worries.

I took as reference this thread, which uses a pool and this one, where I used a queue to do some plots in multiprocessing.

I came up with two codes: the one with the queue works fine on my own computer, but not on the workstations of my lab or on my professional laptop: i have no error messages, it just freezes at some point. The second one works just fine, and I find it simpler than the first example, since I just write directly in the numpy array. (I didn't quite understood the need for all the functions and the init for the async case of the first link.)

My question is: why does my first code have troubles ? I only put below the pieces of code I thought relevant.

Thanks for your help.

First attempt:

def generate_irradiation_maps(rad_v):
    while tasks_queue.empty() == False:
        print("fetching work ...")
        map_index = tasks_queue.get()  # get some work to do from the queue
        print("----> working on map: %s" % map_index)
        perm = range(permsize)
        random.shuffle(perm)
        perm += perm
        for i in range(nb_nodes):
            # call the perlin function: fBm
            rad_v[map_index, i] = fBm(perm, x[i] * freq, y[i] * freq, int(sizex *     freq), int(sizey * freq), octs, persistance)
        rad_v[map_index, :] = rad_v[map_index, :] + abs(min(rad_v[map_index, :]))
        rad_v[map_index, :] = rad_v[map_index, :] / max(rad_v[map_index, :])
        figure = plt.figure(figsize=(20, 7))
        plt.tricontourf(x, y, rad_v[map_index, :])
        plt.axis('image')
        plt.colorbar(shrink=.5)
        figure.savefig('diff_gb_and_pf_irrad_c_map_' + str(map_index) + '.png')
        plt.clf()
        plt.close()
        tasks_queue.task_done()  # work for this item finished

start_time = time.time()
nb_maps = 10
nb_proc = 1  # number of processes

print("generating %d irradiation maps" % nb_maps)
irrad_c_base_array = mp.Array(ctypes.c_double, nb_maps * nb_nodes)  
irrad_c = np.frombuffer(irrad_c_base_array.get_obj())
irrad_c = irrad_c.reshape(nb_maps, nb_nodes)

tasks_queue = mp.JoinableQueue()  # a queue to pile up the work to do

jobs = list(range(nb_maps))  # each job is composed of a map
print("inserting jobs in the queue...")
for job in jobs:
    tasks_queue.put(job)
print("done")

# launch the processes
for i in range(nb_proc):
    current_process = mp.Process(target=generate_irradiation_maps, args=(irrad_c,     ))
    current_process.start()

# wait for all tasks to be treated
tasks_queue.join()

Second attempt:

def generate_irradiation_maps(arg_list):
    map_index = arg_list[0]
    print('working on map %i ' % map_index)
    perm = range(permsize)
    random.shuffle(perm)
    perm += perm
    for i in range(nb_nodes):
        arg_list[1][i] = fBm(perm, x[i] * freq, y[i] * freq, int(sizex * freq),     int(sizey * freq), octs, persistance)
    arg_list[1][:] = arg_list[1][:] + abs(min(arg_list[1][:]))
    arg_list[1][:] = arg_list[1][:] / max(arg_list[1][:])
# plot
figure = plt.figure(figsize=(20, 7))
#plt.tricontourf(x, y, rad_v[map_index, :])
plt.tricontourf(x, y, arg_list[1][:])
plt.axis('image')
plt.colorbar(shrink=.5)
figure.savefig('diff_gb_and_pf_irrad_c_map_' + str(map_index) + '.png')
plt.clf()
plt.close()


start_time = time.time()
nb_maps = 2
nb_proc = 2  # number of processes

print("generating %d irradiation maps" % nb_maps)
irrad_c_base_array = mp.Array(ctypes.c_double, nb_maps * nb_nodes)  # we build     shared array, accessible from all process. we don't access the same zones.
irrad_c = np.frombuffer(irrad_c_base_array.get_obj())
irrad_c = irrad_c.reshape(nb_maps, nb_nodes)

args = [[i,irrad_c[i,:]] for i in range(nb_maps)]

with closing(mp.Pool(processes=nb_proc)) as jobs_pool:
    jobs_pool.map_async(generate_irradiation_maps,args)
jobs_pool.join()
Community
  • 1
  • 1
Napseis
  • 833
  • 2
  • 10
  • 24

1 Answers1

0

I personally have a lot of trouble with multiprocessing. This blog post suggests a possibility. If you are switching between a POSIX and Windows operating system (i.e. from Linux, Unix or Mac) the behavior for spinning out sub-processes is different. The end of the blog post suggests adding the following lines of code to help prevent your processes from deadlocking.

from multiprocessing import set_start_method
set_start_method("spawn")

Unfortunately, the code you shared is not self contained so I cannot test it. If it is possible that you are executing the code on different operating systems then try this out and see if it helps!

Adam Jones
  • 76
  • 9