7

Mein Code (Teil eines genetischen Optimierungsalgorithmus) läuft ein paar Prozesse parallel, wartet auf alle von ihnen zu Ende, liest die Ausgabe und wiederholt dann mit einer anderen Eingabe. Alles hat gut funktioniert, als ich mit 60 Wiederholungen getestet habe. Da es funktionierte, habe ich eine realistischere Anzahl der Wiederholungen verwenden beschlossen, erhielt 200. ich diesen Fehler:Python kann keinen Speicher mit multiprocessing.pool zuweisen

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 

Hier ein Ausschnitt aus meinem Code, der Pool verwendet:

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 

Die RunOne Funktion erstellt ein Objekt in der Klasse, die ich erstellt habe, verwendet ein rechenintensives Python-Paket, um ein Chemieproblem zu lösen, das etwa 30 Sekunden dauert, und gibt das Objekt mit der Ausgabe des Chemie-Solver zurück.

Also ruft mein Code RunMany in Serie, und RunMany ruft dann RunOne parallel auf. In meinen Tests habe ich RunOne mit 10 Prozessoren (der Computer hat 16) und einem Pool von 20 Aufrufen von RunOne aufgerufen. Mit anderen Worten, len (arg1) * len (arg2) * len (arg3) = 20. Alles hat gut funktioniert, als mein Code 60 Mal RunMany aufgerufen hat, aber ich hatte keinen Speicher mehr, als ich 200 Mal anrief.

Bedeutet dies, dass einige Prozesse nicht korrekt aufgeräumt werden? Habe ich ein Speicherleck? Wie kann ich feststellen, ob ich ein Speicherleck habe und wie ich die Ursache des Lecks herausfinden kann? Das einzige Element, das in meiner 200-Wiederholungsschleife wächst, ist eine Liste von Zahlen, die von 0 bis 200 zunimmt. Ich habe ein Wörterbuch mit Objekten aus einer benutzerdefinierten Klasse, die ich gebaut habe, aber es ist auf eine Länge begrenzt von 50 Einträgen - jedes Mal, wenn die Schleife ausgeführt wird, löscht sie ein Element aus dem Wörterbuch und ersetzt es durch ein anderes Element.

Edit: Hier ist ein Ausschnitt aus dem Code, den 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") 
+1

Da es nun die „Ergebnisse“ in keinem Verhältnis wachsen sehr schnell gehen, und wenn das passiert - Sie werden über genügend Arbeitsspeicher ausgeführt, wie Sie nie geöffnet schließen Pool von Prozessen. –

+0

Puciek: "Ergebnisse" hat höchstens 20 Einträge. Die RunMany-Funktion wird von meiner Hauptfunktion aufgerufen, und "Ergebnisse" ist lokal für die RunMany-Funktion. Kann es als lokale Variable nicht gelöscht werden, wenn RunMany beendet ist? Oder funktionieren Pools nicht so? – Jeff

+1

Es soll so funktionieren, aber manchmal Python haben Probleme nach sich selbst aufräumen. Hier ein ähnliches Problem http://stackoverflow.com/questions/24564782/ways-to-free-memory-back-to-os-from-python/24564983#24564983 –

Antwort

10

Wie in den Kommentaren zu meiner Frage ruft gezeigt, ist die Antwort von Puciek kam.

Die Lösung bestand darin, den Prozesspool nach Abschluss zu schließen. Ich dachte, dass es automatisch geschlossen würde, weil die Variable results lokal RunMany ist und nach RunMany gelöscht würde. Python funktioniert jedoch nicht immer wie erwartet.

Der feste Code ist:

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