Mehrfachverarbeitung einer for-Schleife?

75

Ich habe ein Array (genannt data_inputs), das die Namen von Hunderten von Astronomie-Bilddateien enthält. Diese Bilder werden dann manipuliert. Mein Code funktioniert und es dauert einige Sekunden, um jedes Bild zu verarbeiten. Es kann jedoch immer nur ein Bild gleichzeitig erstellt werden, da das Array durch eine forSchleife ausgeführt wird:

for name in data_inputs:
    sci=fits.open(name+'.fits')
    #image is manipulated

Es gibt keinen Grund, warum ich ein Image vor einem anderen ändern muss. Ist es also möglich, alle 4 Kerne auf meinem Computer zu verwenden, wobei jeder Kern durch die for-Schleife auf einem anderen Image läuft?

Ich habe über das multiprocessingModul gelesen , bin mir aber nicht sicher, wie ich es in meinem Fall implementieren soll. Ich bin sehr daran interessiert, mich multiprocessingan die Arbeit zu machen, weil ich dies irgendwann auf über 10.000 Bildern ausführen muss.

ChrisFro
quelle

Antworten:

96

Sie können einfach verwenden multiprocessing.Pool:

from multiprocessing import Pool

def process_image(name):
    sci=fits.open('{}.fits'.format(name))
    <process>

if __name__ == '__main__':
    pool = Pool()                         # Create a multiprocessing Pool
    pool.map(process_image, data_inputs)  # process data_inputs iterable with pool
alko
quelle
13
Es ist möglicherweise besser zu verwenden: pool = Pool(os.cpu_count()) Dies ist eine allgemeinere Methode zur Verwendung von Multiprocessing.
Lior Magen
2
Hinweis: os.cpu_count()wurde in Python 3.4 hinzugefügt. Für Python 2.x verwenden multiprocessing.cpu_count().
Dwj
21
Pool()ist das gleiche wiePool(os.cpu_count())
Tim
16
Die Ausarbeitung des Kommentars von @ Tim - Pool()ohne Wert für aufgerufen - processesist dasselbe wie Pool(processes=cpu_count())unabhängig davon, ob Sie Python 3 oder 2 verwenden Pool(). Daher empfiehlt es sich, in JEDER Version zu verwenden . docs.python.org/2/library/multiprocessing.html
Monkpit
7
@LiorMagen, wenn ich mich nicht irre, wird durch die Verwendung von Pool (os.cpu_count ()) das Betriebssystem eingefroren, bis die Verarbeitung abgeschlossen ist, da Sie dem Betriebssystem keine freien Kerne hinterlassen. Für viele Benutzer könnte Pool (os.cpu_count () - 1) eine bessere Wahl sein
Shayelk
22

Sie können verwenden multiprocessing.Pool:

from multiprocessing import Pool
class Engine(object):
    def __init__(self, parameters):
        self.parameters = parameters
    def __call__(self, filename):
        sci = fits.open(filename + '.fits')
        manipulated = manipulate_image(sci, self.parameters)
        return manipulated

try:
    pool = Pool(8) # on 8 processors
    engine = Engine(my_parameters)
    data_outputs = pool.map(engine, data_inputs)
finally: # To make sure processes are closed in the end, even if errors happen
    pool.close()
    pool.join()
ixxo
quelle
1
Ich kann hier nicht verstehen, was "data_inputs" ist. Du hast es nicht definiert. Welchen Wert soll ich geben?
Abhishek dot py
1
Es ergibt sich tatsächlich aus der Antwort von alko. Ich zitiere seinen Kommentar (siehe Codeblock): "verarbeitet data_inputs, die mit pool iteriert werden können". So data_inputsist eine iterable (wie in einem Standard map).
Ponadto
Das Python-Dokument zeigt nur, dass man eine Funktion an übergeben kann pool.map(func, iterable[, chunksize]). Wird dieses Objekt beim Übergeben eines Objekts von allen Prozessen gemeinsam genutzt? Könnte ich also alle Prozesse in dieselbe Liste self.list_im Objekt schreiben lassen ?
Philipp
5

Alternative

with Pool() as pool: 
    pool.map(fits.open, [name + '.fits' for name in datainput])
Spas
quelle
TypeError: 'Pool' object is not callable
Chris
Entschuldigung, mein Fehler ist "pool.map", nicht nur "pool". Ich habe es repariert.
Spas