I am writing a genetic optimization algorithm based on the deap package in python 2.7 (goal is to migrate to python 3 soon). As it is a pretty heavy process, some parts of the optimisation are processed using the multiprocessing package. Here is a summary outline of my program:
- Configurations are read in and saved in a
configobject - Some additional pre-computations are made and saved as well in the
configobject - The optimisation starts (population is initialized randomly and mutations, crossover is applied to find a better solution) and some parts of it (evaluation function) are executed in multiprocessing
- The results are saved
For the evaluation function, we need to have access to some parts of the config object (which after phase 2 stays a constant). Therefore we make it accessible to the different cores using a global (constant) variable:
from deap import base
import multiprocessing
toolbox = base.Toolbox()
def evaluate(ind):
# compute evaluation using config object
return(obj1,obj2)
toolbox.register('evaluate',evaluate)
def init_pool_global_vars(self, _config):
global config
config = _config
...
# setting up multiprocessing
pool = multiprocessing.Pool(processes=72, initializer=self.init_pool_global_vars,
initargs=[config])
toolbox.register('map', pool.map_async)
...
while tic < max_time:
# creating new individuals
# computing in optimisation the objective function on the different individuals
jobs = toolbox.map(toolbox.evaluate, ind)
fits = jobs.get()
# keeping best individuals
We basically make different iterations (big for loop) until a maximum time is reached. I have noticed that if I make the config object bigger (i.e. add big attributes to it, like a big numpy array) even if the code is still same it runs much slower (fewer iterations for the same timespan). So I thought I would make a specific config_multiprocessing object that contains only the attributes needed in the multiprocessing part and pass that as a global variable, but when I run it on 3 cores it is slower than with the big config object and on 72 cores, it is slightly faster, but not much.
What should I do in order to make sure my loops don't suffer in speed from the config object or from any other data manipulations I make before launching the multiprocessing loops?
Running in a Linux docker image on a linux VM in the cloud.
multiprocessing.Poolat the start, I don't have yet my config object created, as such I cannot initialize the different executors with the object as a global variable (as at the beginning, it does not exist yet or not complete yet) - ThomasPoolwill inherit the state (memory) from the parent process which gets pickled for transfer. Hence if you make yourconfigobject bigger, more pickling needs to be done and more memory needs to copied. Since the sub-processes inherit the global state anyway, it's not necessary to use that extra initializer function. When you create your specificconfig_multiprocessing, supposedly derived fromconfig, did youdel configbefore spawning the pool? Because if not then both objectsconfig_multiprocessingandconfigwill be copied to the sub-processes. - a_guestpool = multiprocessing.Pool(processes=config.nProcesses)) I have an error saying that config is not definedNameError: global name 'config' is not definedI am running inside a linux docker container so there the sub-process created by pool does not inherit the state of the parent! - Thomas