Parallelisierter For-Loop

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
sp
User
Beiträge: 2
Registriert: Sonntag 7. Oktober 2007, 10:23

Freitag 23. Mai 2008, 20:08

Hallo

Ich habe eine Liste von Objekten, die initialisiert werden müssen. Die Initialisierung der einzelnen Objekte kann aufgrund externer Abhängigkeiten relativ lange dauern. Im Moment initialisiere ich die Objekte, indem ich über eine Liste der Objekte iteriere. Da die einzelnen Objekte nicht von einander abängig sind, würde ich diesen Vorgang gerne parallelisieren.

Gibt es eine Möglichkeit, aller OpenMP, For-Loops in Python auf einfache Art und Weise zu parallelisieren? Oder habt ihr vielleicht einen Vorschlag, wie ich dieses Problem eleganter lösen kann?

Vielen Dank für eure Hilfe.
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Freitag 23. Mai 2008, 20:16

Das wird so wie du es dir wünscht vermutlich nicht gehen, denn CPython hat ein globales Lock (GIL), welches verhindert, dass gleichzeitig in mehreren Threads Python-Code ausgeführt wird. Das wird also nur gehen, wenn ein großer Teil deines Codes in C geschrieben ist.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

Freitag 23. Mai 2008, 20:21

PyProcessing bietet solche Sachen an. Da gibt es zum Beispiel map_async. Eine genaue Antwort wird dir jedoch niemand geben können ohne das Problem genauer zu kennen.
[url=http://29a.ch/]My Website - 29a.ch[/url]
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
sp
User
Beiträge: 2
Registriert: Sonntag 7. Oktober 2007, 10:23

Freitag 23. Mai 2008, 20:42

Danke für eure Antworten.

Die Zeit verstreicht größtenteils beim Warten auf I/O-Anfragen bzw. HTTP und FTP Anfragen. Wird der GIL von den built-in Klassen für HTTP und FTP freigegeben?

Code: Alles auswählen

objekte = [obj1, obj2, obj3, obj4]

for obj in objekte:
   obj.initialisierung() # kann bis zu 10 sekunden dauern, da daten von externen "quellen" geladen werden

# an diesem punkt wären alle objekte initialisiert, allerdings könnte es in diesem beispiel bis zu 40 sekunden dauern
Meine Idee war nun, den Vorgang zu beschleunigen, indem die einzelnen "Initialisierungen" mehr oder weniger parallel ausgeführt werden.

Code: Alles auswählen

objekte = [obj1, obj2, obj3, obj4]

for obj in objekte:
   ausführenInNeuemThread(obj.initialisierung()) # kann bis zu 10 sekunden dauern, da daten von externen "quellen" geladen werden

warteBisAlleThreadsBeendetSind()
Die Anzahl der Objekte ist erst zur Laufzeit bekannt. Es klingt vermutlich viel aufwendiger, als es ist ;).
EyDu
User
Beiträge: 4871
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Freitag 23. Mai 2008, 21:16

Bei IO-Anfragen wir er freigegeben. Nimm einfach eine ganze Menge an Threads die die Anfragen durchführen, und das Ergebnis in eine Queue stecken. Ein weiterer Thread arbeitet dann die Queue ab.
tux21b
User
Beiträge: 18
Registriert: Mittwoch 15. Februar 2006, 23:20
Wohnort: Linz.at
Kontaktdaten:

Sonntag 25. Mai 2008, 23:04

bleib bei openmp und c *duck*

Ich bin auch ein Python Fan, aber Multiprocessing ist mit omp einfach viel angenehmer in c...
[url]http://www.ubuntuusers.de[/url]
EyDu
User
Beiträge: 4871
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Sonntag 25. Mai 2008, 23:38

Du meinst noch einfacher als das hier?

Code: Alles auswählen

import threading
import Queue

#tasks
input_queue = Queue.Queue()

#results
result_queue = Queue.Queue()


class Worker(threading.Thread):
    def run(self):
        while True:
            #get new task
            task = input_queue.get()

            #process task
            result = ...(task)...

            result_queue.put(result)


class Consumer(threading.Thread):
    def run(self):
        while True:
            #wait for new result
            result = result_queue.get()

            #process result
            ...result...


#fill input queue...

#start consumer
consumer = Consumer()
consumer.start()

#workers
workers = [Worker() for x in range(NUM_WORKERS)]
for worker in workers:
    worker.start()

consumer.join()
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Montag 26. Mai 2008, 08:28

EyDu hat geschrieben:Du meinst noch einfacher als das hier?
Zuerst der Klassiker: In Erlang ist es einfacher. Jetzt das Problem: In Python hast du das nette GIL und da wird nur ein Kern gleichzeitig arbeiten. Workaround: forken, und da fängt es dann an, dass openmp mehr Spaß macht.
TUFKAB – the user formerly known as blackbird
BlackJack

Montag 26. Mai 2008, 09:36

Wenn man das alles selber schreibt, und wie sieht's mit Bibliotheken wie Parallel Python (`pp`) oder Pyro aus?

Und im vorliegenden Fall ist der Ansatz von EyDu auch schon wertvoll, da es ja um blockierendes IO geht und dort das GIL freigegeben wird.
Antworten