Python no puede asignar memoria utilizando multiprocessing.pool

Mi código (parte de un algoritmo de optimización genética) ejecuta algunos procesos en paralelo, espera a que todos terminen, lee la salida y luego se repite con una entrada diferente. Todo funcionaba bien cuando lo probé con 60 repeticiones. Como funcionó, decidí usar un número más realista de repeticiones, 200. Recibí este error:

File "/usr/lib/python2.7/threading.py", line 551, in __bootstrap_inner self.run() File "/usr/lib/python2.7/threading.py", line 504, in run self.__target(*self.__args, **self.__kwargs) File "/usr/lib/python2.7/multiprocessing/pool.py", line 302, in _handle_workers pool._maintain_pool() File "/usr/lib/python2.7/multiprocessing/pool.py", line 206, in _maintain_pool self._repopulate_pool() File "/usr/lib/python2.7/multiprocessing/pool.py", line 199, in _repopulate_pool w.start() File "/usr/lib/python2.7/multiprocessing/process.py", line 130, in start self._popen = Popen(self) File "/usr/lib/python2.7/multiprocessing/forking.py", line 120, in __init__ self.pid = os.fork() OSError: [Errno 12] Cannot allocate memory 

Aquí hay un fragmento de mi código que usa pool:

 def RunMany(inputs): from multiprocessing import cpu_count, Pool proc=inputs[0] pool=Pool(processes = proc) results=[] for arg1 in inputs[1]: for arg2 in inputs[2]: for arg3 in inputs[3]: results.append(pool.apply_async(RunOne, args=(arg1, arg2, arg3))) casenum=0 datadict=dict() for p in results: #get results of simulation once it has finished datadict[casenum]=p.get() casenum+=1 return datadict 

La función RunOne crea un objeto en la clase que creé, usa un paquete de Python de gran peso computacional para resolver un problema de química que demora unos 30 segundos y devuelve el objeto con la salida del solucionador de química.

Entonces, mi código llama a RunMany en serie, y RunMany llama a RunOne en paralelo. En mis pruebas, llamé a RunOne usando 10 procesadores (la computadora tiene 16) y un grupo de 20 llamadas a RunOne. En otras palabras, len (arg1) * len (arg2) * len (arg3) = 20. Todo funcionó bien cuando mi código llamó RunMany 60 veces, pero me quedé sin memoria cuando lo llamé 200 veces.

¿Significa esto que algún proceso no se está limpiando correctamente? ¿Tengo una pérdida de memoria? ¿Cómo puedo determinar si tengo una pérdida de memoria y cómo puedo averiguar la causa de la pérdida? El único elemento que está creciendo en mi ciclo de 200 repeticiones es una lista de números que crece del tamaño 0 a una longitud de 200. Tengo un diccionario de objetos de una clase personalizada que he construido, pero está limitado en una longitud de 50 entradas: cada vez que se ejecuta el bucle, elimina un elemento del diccionario y lo reemplaza por otro.

Edición: aquí hay un fragmento del código que llama a RunMany

 for run in range(nruns): #create inputs object for RunMany using genetic methods. #Either use starting "population" or create "child" inputs from successful previous runs datadict = RunMany(inputs) sumsquare=0 for i in range(len(datadictsenk)): #input condition sumsquare+=Compare(datadict[i],Target[i]) #compare result to target with open(os.path.join(mainpath,'Outputs','output.txt'),'a') as f: f.write('\t'.join([str(x) for x in [inputs.name, sumsquare]])+'\n') Objective.append(sumsquare) #add sum of squares to list, to be plotted outside of loop population[inputs]=sumsquare #add/update the model in the "population", using the inputs object as a key, and it's objective function as the value if len(population)>initialpopulation: population = PopulationReduction(population) #reduce the "population" by "killing" unfit "genes" avgtime=(datetime.datetime.now()-starttime2)//(run+1) remaining=(nruns-run-1)*avgtime print(' Finished '+str(run+1)+' / ' +str(nruns)+'. Elapsed: '+str(datetime.datetime.now().replace(microsecond=0)-starttime)+' Remaining: '+str(remaining)+' Finish at '+str((datetime.datetime.now()+remaining).replace(microsecond=0))+'~~~', end="\r") 

Como se muestra en los comentarios a mi pregunta, la respuesta vino de Puciek.

La solución fue cerrar el conjunto de procesos una vez finalizado. Pensé que se cerraría automáticamente porque la variable de results es local a RunMany y se eliminaría después de que RunMany completara. Sin embargo, Python no siempre funciona como se espera.

El código fijo es:

 def RunMany(inputs): from multiprocessing import cpu_count, Pool proc=inputs[0] pool=Pool(processes = proc) results=[] for arg1 in inputs[1]: for arg2 in inputs[2]: for arg3 in inputs[3]: results.append(pool.apply_async(RunOne, args=(arg1, arg2, arg3))) #new section pool.close() pool.join() #end new section casenum=0 datadict=dict() for p in results: #get results of simulation once it has finished datadict[casenum]=p.get() casenum+=1 return datadict