Seite 1 von 1

parallel python

Verfasst: Montag 12. April 2010, 15:08
von Heini
Folgende Ausgangssituation:
Bei parallel python geht das doch folgendermaßen

Code: Alles auswählen


import pp, scipy

def h(b):
    return scipy.cos(b)**2

def func1(a):
    return scipy.sin(a)**h(b)

job_server = pp.Server()

f1 = job_server.submit(func1, (1,), ('h',), ('scipy',))

Soweit ist das ja ein ganz nettes Spielzeug, aber was mache ich jetzt wenn statt einer Funktion a la 'h', unangenehm viele Funktionen gibt, die auch noch in verschiedenen Dateien und Verzeichnissen liegen?
Das Tuple der Module wird doch auch unangenehm lang.
Und muss ich alle 'scipy'-Funktionen (oder von welchem Modul auch immer) innerhalb von 'func1' dann mit 'scipy.sin' aufrufen?

Gruß

Verfasst: Montag 12. April 2010, 15:48
von CM
Hoi

Bei der ersten Frage fallen mir pp.Templates ein. Ggf. solltest Du auch refactorn und Deinen Code den Bedürfnissen von pp anpassen, so daß eben weniger Funktionen aufzurufen sind. Ein Weg ist ggf. eine OO-Ausdrucksweise Deines Problems, bei dem die Methoden einer Klasse einander aufrufen. Das allerdings ist nicht immer sinnvoll und manchmal sicher eher verwirrend.

Zur zweiten Frage: Keine Ahnung. Aber Du kannst ja mal Shorthand, a la "import longlonglongname as ln" benutzen. Funktioniert das? (Kann ich gerade nicht probieren ...)

HTH
Christian

PS Magst Du Deinen ersten Beitrag im Thread korrigieren? Ist so ja schlecht lesbar.

Verfasst: Dienstag 13. April 2010, 09:39
von Heini
Ich bin mir immer beim OO nicht so ganz sicher wer auf was zugreift und wie ich dann das Objekt oder die Instanz übergebe, wenn ich dann eine Methode parallelisieren möchte.

Hier mal ein Minimalbeispiel wie ich es mir gedacht habe, dass es funktionieren könnte (was es nicht tut):

Code: Alles auswählen

import pp

class cl(object):
    def __init__(self,a):
        #irgendwelche zahlen
        self.a = a
    
    def int_func(self,x):
        #irgendeine funktion,soll parallelisiert werden
        return x**self.a
    
    def func(self,y):
        #ruft ein paar mal int_func auf,das soll parallel geschehen
        j = pp.Server()
        js = {}
        r=0
        
        #jobs creieren
        for i in xrange(10):
            js[repr(i)] = j.submit(self.int_func, (y,),(),())
        
        #ergebnisse einfordern
        for i in xrange(10):
            print js[repr(i)]()
        
        return r

b = cl(10)
print b.func(4)

Dann bekomme ich einen endlos langen Fehler (s.u.) wobei das Skript dann noch nicht mal abbricht, also eigentlich noch weiter läuft - ohne etwas zu machen. Auch die Übergabe von 'cl' als Modul oder 'b' als Instanzname hilft da nicht. Ich bin mir sicher dass das irgendwie geht und dass es wahrscheinlich alle wissen außer mir.




Fatal error has occured during the function execution
Traceback (most recent call last):
File "C:\progra~1\Python25\lib\site-packages\ppworker.py", line 91, in run
args = pickle.loads(s)
AttributeError: 'module' object has no attribute 'cl'
None
Fatal error has occured during the function execution
Traceback (most recent call last):
File "C:\progra~1\Python25\lib\site-packages\ppworker.py", line 91, in run
args = pickle.loads(s)
AttributeError: 'module' object has no attribute 'cl'
None
Traceback (most recent call last):
File "C:\Program Files\Python25\Lib\site-packages\pp.py", line 485, in __run
worker.t.csend(sfunc)
File "C:\Program Files\Python25\Lib\site-packages\pptransport.py", line 64, in
csend
self.send("H" + hash1)
File "C:\Program Files\Python25\Lib\site-packages\pptransport.py", line 91, in
send
self.w.write(str(len(msg))+"\n")
IOError: [Errno 22] Invalid argument
Unhandled exception in thread started by
Traceback (most recent call last):
File "C:\Program Files\Python25\Lib\site-packages\pp.py", line 496, in __run
job.finalize(sresult)
UnboundLocalError: local variable 'sresult' referenced before assignment
Traceback (most recent call last):
File "C:\Program Files\Python25\Lib\site-packages\pp.py", line 487, in __run
sresult = worker.t.receive()
File "C:\Program Files\Python25\Lib\site-packages\pptransport.py", line 97, in
receive
msg_len = int(s)
ValueError: invalid literal for int() with base 10: ''
Unhandled exception in thread started by
Traceback (most recent call last):
File "C:\Program Files\Python25\Lib\site-packages\pp.py", line 496, in __run
job.finalize(sresult)
UnboundLocalError: local variable 'sresult' referenced before assignment

Verfasst: Dienstag 13. April 2010, 09:52
von CM
So bekommst Du Ärger mit der Serialisierung (edit: oder wie auch immer der korrekte Terminus Technikus im Falle von pp ist) ...

Nein, was ich meinte ist in etwa das:

Code: Alles auswählen

class MyClass(object):
    ....
    def _heavy_calcs(self, ....): pass
    def modify_object(self, ...):
         ...
         _heavy_calcs(...)

# Objekt anlegen
m = MyClass(....)
...
j.submit(m.modify_object, ...)
Aber, wie gesagt: Wenn der Ansatz, Dir für Dein Problem semantisch verschroben erscheint, nutze pp.Templates.

HTH
Christian

Verfasst: Dienstag 13. April 2010, 11:13
von Heini
Naja, das Problem ist wirklich, dass ich _heavy_calcs parallel laufen lassen möchte, nicht die aufgerufene, bzw. aufrufende Funktion, und mein Programm ja schon OO ist. Das jetzt alles nochmal umzuschreiben...um Gottes Willen.

Verfasst: Dienstag 13. April 2010, 11:33
von CM
Na ja, die Idee wäre halt chunks auf eine Liste von Objekte aufzuteilen. Nochmals: Das läßt sich nicht unbedingt einfach / sinnvoll realisieren.

Hast Du schon einen Blick auf den Templates-Link geworfen? Damit solltest Du eigentlich Dein Problem mit Hausmitteln lösen können.

Verfasst: Dienstag 13. April 2010, 12:08
von Heini
Hab ich, aber wie ich es jetzt verstehe stoße ich mit meiner OO-Struktur an die Grenze.

Verfasst: Mittwoch 14. April 2010, 09:40
von CM
Dann laß mal realistischen Code sehen - am besten in ein Minimalbeispiel in einem past bin. Ansonsten bleiben wir zu lange im Ungefähren.

Verfasst: Mittwoch 14. April 2010, 11:35
von Heini
Okay, ich versuch's. Den ganzen Code kann ich natürlich schlecht posten, aber im wesentlichen sieht die Struktur schon wie im 2. Beispiel aus, also:

Code: Alles auswählen

import pp, scipy.optimize

class cl(object):
    
    def __init__(self,a):
        #irgendwelche zahlen
        self.a = a
    
    def heavy_calc(self,x):
        #irgendeine funktion,soll parallelisiert werden
        
        #in der realitaet werden hier recht grosse numpy-arrays
        #multipliziert und summiert
        #dabei wird glueckicherweise nur auf Attribute der Instanz und nicht
        #auf Methoden zugegriffen (falls das eine Rolle spielt)
        return x**self.a
    
    def multiple_heavy_calcs(self,y):
        #ruft einige male hintereinander int_func auf,
        #das soll parallel geschehen
        
        #in der realitaet wird hier eine Matrix erstellt
        #dazu wird durch die indizes iteriert
        #mein erster ansatz nutzte ausschliesslich numpy-arrays
        #leider wurden die arrays dann sehr gross
        #(ab einer groesse von 64x64x64x64 bekomme ich einen memory error,
        #float64,tatsaechlich haette die groesste matrix 8 dimensionen zu je
        #ca. 64 eintraegen - nach meiner rechnung brauche ich da gar nciht
        #drueber nachdenken dass in einen array zu packen)
        j = pp.Server()
        js = {}
        r=0
        
        #jobs creieren
        for i in xrange(10):
            js[repr(i)] = j.submit(self.heavy_calc, (y,),(),())
        
        #ergebnisse einfordern
        for i in xrange(10):
            #das wollte ich eigentlich machen
            #r += js[repr(i)]()
            
            #um das aber mal zu demonstrieren:
            print js[repr(i)]()
        
        return r
    
    def result(self,x0,x1):
        #diese letzte funktion wird dann tatsaechlich aufgerufen
        
        #in der realitaet wird die nullstelle der determinante der matrix gesucht
        return scipy.optimize.brentq(self.multiple_heavy_calcs, x0,x1)

b = cl(10)
print b.result(0,1000)

So ich hoffe das ist genug Code um daraus schlau zu werden, aber klein genug um als Minimalbeispiel durchzugehen.
So wie ich es verstehe liegt das Problem also darin, dass ich versuche eine methode zu parallelisieren, die letztendlich nur von anderen methoden aufgerufen wird. Stimmt das so in etwa?

P.S.: wenn ich numpy tatsächlich benutze, dann bekomme ich noch die Fehlermeldung dass numpy-arrays nicht hashable sind.

Verfasst: Freitag 16. April 2010, 15:34
von CM
Heini hat geschrieben:Okay, ich versuch's. Den ganzen Code kann ich natürlich schlecht posten, aber im wesentlichen sieht die Struktur schon wie im 2. Beispiel aus, ...
In der Tat: Und da haben wir zwei Probleme:
1. Es funktioniert nicht, weil es a) anders umgesetzt als mein Beispiel und b) so nicht serialisierbar ist (das Objekt muß ja auch an einen (externen) Knoten gesendet werden können.
2. Und weil so numpy-Arrays auch nicht verwendet werden können - was mir neu war, aber tatsächlich im Netz zu finden ist.

Aber das weicht doch total von Deiner ursprünglichen Fragestellung ab. Wenn Du zum Schluß kommst, dass OO hier nicht der Weisheit letzter Schluß ist, warum dann probieren?

Eigentlich meinte mit meinem letzten Post auch wieder den Template-Ansatz. Der müßte es Dir ermöglichen die Liste der Funktionen und Modul auf eine Angabe zu beschränken und den Code wieder übersichtlich zu machen. Gibt es damit ein Problem?

Gruß,
Christian

Verfasst: Sonntag 18. April 2010, 13:06
von Heini
Das Problem ist eben, dass die Programmstruktur genau so aussieht wie in dem Beispiel. Ich müsste also das ganze Programm umschreiben. Und da dann noch numpy-Array-Probleme auf mich zukommen...eigentlich macht die Funktion doch gar nicht viel - nur ein paar Grundrechenarten an Arrays ausführen und die Arrays aus der Instanz holen. Ach mist...darüber hätte man sich mal vorher Gedanken machen müssen - aber so ist das, man programmiert einfach drauf los und irgendwann steht man in einer Sackgasse und muss umkehren.

Als ich den Post geschrieben habe, dachte ich ja auch noch es geht darum eine elendig lange Liste mit Modulen zu übergeben und das ganze ein bisschen zu vereinfachen. Templates wären in dem Fall genau das richtige.