@hera: Also Du bekommst dort den gleichen Pfad vom `pickle`-Modul ausgegeben? Mein Verdacht ist/war ja, dass Du da noch irgendwo ein Modul hast, was `pickle` heisst, aber eben ein anderes ist. Was wird denn direkt vor der `Pool`-Zuweisung ausgegeben wenn Du ``print dir(pickle)`` ausführst? Sind da die erwarteten Namen ausser dem `Pickler` oder ganz was anderes?
Startest Du das eigentlich auf der Konsole, oder aus einer IDE heraus? IDEs sind auch gerne mal Fehlerquellen, wenn sie die Laufzeitumgebung von Python beeinflussen.
`map()` wendet eine Funktion auf die einzelnen Elemente einer Liste (bzw. allgemein ein iterierbares Objekt) an und erzeugt eine Liste mit den Ergebnissen dieser Aufrufe. `multiprocessing.Pool.map()` führt dabei die Funktion auf verschiedenen Elementen parallel in verschiedenen Prozessen aus.
Multiprocessing - wie richtig nutzen?
Hallo BlackJack,
wenn ich print(dir(pickle)) aufrufe, wird folgendes ausgegeben:
['__builtins__', '__doc__', '__file__', '__name__', '__package__']
Hilft das?
Ansonsten gibts dann dieselbe Fehlermeldung wie zuvor gepostet.
Ich starte aus eclipse, gab bislang aber auch noch nie Probleme - was ja nix heißen mag.
Danke für die Erläuterung zur Funktion map(), habe ich soweit inzwischen durchschaut. Für mich war mehr die Frage, ob es denn nun auch an der richtigen Stellt steht, also innerhalb der Funktion, die in parallelen Prozessen gestartet werden soll.
Gruß, HeRa
wenn ich print(dir(pickle)) aufrufe, wird folgendes ausgegeben:
['__builtins__', '__doc__', '__file__', '__name__', '__package__']
Hilft das?
Ansonsten gibts dann dieselbe Fehlermeldung wie zuvor gepostet.
Ich starte aus eclipse, gab bislang aber auch noch nie Probleme - was ja nix heißen mag.
Danke für die Erläuterung zur Funktion map(), habe ich soweit inzwischen durchschaut. Für mich war mehr die Frage, ob es denn nun auch an der richtigen Stellt steht, also innerhalb der Funktion, die in parallelen Prozessen gestartet werden soll.
Gruß, HeRa
@hera: Und bei der Pfadangabe wenn Du das Modul selbst ``print``\est ist auch der Pfad zur Standardbibliothek? Das ist sehr eigenartig.
Und natürlich ist die Funktion die parallel abgearbeitet werden soll nicht der Ort um `map()` zu verwenden, denn `map()` muss man ja genau die Funktion als Argument übergeben, die dann parallel ausgeführt wird. Da müsste man dann ja die Funktion die das `map()` enthält übergeben, damit die sich selber parallel ausführt und dabei dann sich selbst an `map()` übergibt, und dann parallel ausgeführt wird, wobei dort die Funktion an `map()` übergeben wird, um dann parallel ausgeführt zu werden, wobei…
*So* bekommt man auch unendlich viele Prozesse hin, beziehungsweise bis zu der Grenze wo das Betriebssystem darauf keine Lust mehr hat.
Und natürlich ist die Funktion die parallel abgearbeitet werden soll nicht der Ort um `map()` zu verwenden, denn `map()` muss man ja genau die Funktion als Argument übergeben, die dann parallel ausgeführt wird. Da müsste man dann ja die Funktion die das `map()` enthält übergeben, damit die sich selber parallel ausführt und dabei dann sich selbst an `map()` übergibt, und dann parallel ausgeführt wird, wobei dort die Funktion an `map()` übergeben wird, um dann parallel ausgeführt zu werden, wobei…
*So* bekommt man auch unendlich viele Prozesse hin, beziehungsweise bis zu der Grenze wo das Betriebssystem darauf keine Lust mehr hat.
@BlackJack:
ja, genau genommen siehts von den Aufrufen jetzt so aus, dass die Funktion, die parallelisiert aufgerufen werden soll, in map() übergeben wird. Ich vermute mal, dass ist jetzt der Weg, wie map() zu nutzen ist (ok, so ganz sicher bin ich mir da natürlich nicht).
Was könnte ich denn noch an Infos liefern, um über dieses eigenartige Verhalten und zur Parallelisierung beizutragen. Wäre froh, zu einer Lösung finden zu können.
ja, genau genommen siehts von den Aufrufen jetzt so aus, dass die Funktion, die parallelisiert aufgerufen werden soll, in map() übergeben wird. Ich vermute mal, dass ist jetzt der Weg, wie map() zu nutzen ist (ok, so ganz sicher bin ich mir da natürlich nicht).
Was könnte ich denn noch an Infos liefern, um über dieses eigenartige Verhalten und zur Parallelisierung beizutragen. Wäre froh, zu einer Lösung finden zu können.
Eine weitere Sache ist mir aufgefallen.
In der Fehlermeldung wird ja forking.py aufgelistet. forking.py enthält folgenden Code:
Wenn ich nun versuche ausschließlich diesen Code auszuführen, gibts dieselbe Fehlermeldung:
Frage nun, warum findet er den Pickler nicht? Und was macht der Pickler eigentlich?
In der Fehlermeldung wird ja forking.py aufgelistet. forking.py enthält folgenden Code:
Code: Alles auswählen
from pickle import Pickler
print(Pickler)
Code: Alles auswählen
from pickle import Pickler
ImportError: cannot import name Pickler
@hera: Wo kommt denn das ``print(Pickler)`` her? Das gehört da ziemlich sicher nicht hinein.
Du hast auch immer noch nicht verraten was ``import pickle; print pickle`` ausgibt wenn Du das in Deinem Code vor die Zeile platzierst, welche zu der Ausnahme führt. Denn wenn das Modul leer ist, kann es ja nicht das aus der Standardbibliothek sein. Und das ganze bitte ohne Eclipse ausführen.
Du hast auch immer noch nicht verraten was ``import pickle; print pickle`` ausgibt wenn Du das in Deinem Code vor die Zeile platzierst, welche zu der Ausnahme führt. Denn wenn das Modul leer ist, kann es ja nicht das aus der Standardbibliothek sein. Und das ganze bitte ohne Eclipse ausführen.
@BlackJack:
ich habe den Code jetzt mal nicht aus der IDE aus gestartet, sondern direkt. Das Problem mit dem Pickler tritt dann nicht auf.
Jetzt erhalte ich diese Fehlermeldung, die ja sehr aussagekräftig ist und den Hinweis mit freeze_support() enthält:
Aber: ich habe keine __main__ in meinem Programm drin. Python rufe ich direkt über eine batch auf mit Übergabeparametern.
Muss if __name__ == '__main__' im Programm enthalten sein, um freeze_support zu nutzen?
Habe den freeze_support() Befehl mal direkt vor
gesetzt.
Das hat jetzt keine Abhilfe geschaffen, die Fehlermeldung taucht weiterhin auf.
Zuversichtlich stimmt mich jetzt aber: Wenn ich den Prozessverlauf im Taskmanager anschaue bleibts aber jetzt schon bei den maximal 7 Aufrufen und die Prozesse verschwinden nach der Ausführung, also keine Endlosschleife mehr.
Was könnte ich noch ändern?
ich habe den Code jetzt mal nicht aus der IDE aus gestartet, sondern direkt. Das Problem mit dem Pickler tritt dann nicht auf.
Jetzt erhalte ich diese Fehlermeldung, die ja sehr aussagekräftig ist und den Hinweis mit freeze_support() enthält:
Code: Alles auswählen
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "C:\Python27\lib\multiprocessing\forking.py", line 380, in main
prepare(preparation_data)
File "C:\Python27\lib\multiprocessing\forking.py", line 495, in prepare
'__parents_main__', file, path_name, etc
File "C:\myProg\program_control.py", line 746, in <module>
lauf(data)
File "C:\myProg\program_control.py", line 232, in lauf
rn.cg(instanz_name, None, max_labels_to_create)
File "C:\myProg\Node.py", line 159, in cg
LABE_aller_perioden = self.solve_KW(arcs_to_forbid, max_labels_to_create)
File "C:\myProg\Node.py", line 121, in solve_KW
pool = multiprocessing.Pool()
File "C:\Python27\lib\multiprocessing\__init__.py", line 232, in Pool
return Pool(processes, initializer, initargs, maxtasksperchild)
File "C:\Python27\lib\multiprocessing\pool.py", line 159, in __init__
self._repopulate_pool()
File "C:\Python27\lib\multiprocessing\pool.py", line 222, in _repopulate_pool
w.start()
File "C:\Python27\lib\multiprocessing\process.py", line 130, in start
self._popen = Popen(self)
File "C:\Python27\lib\multiprocessing\forking.py", line 258, in __init__
cmd = get_command_line() + [rhandle]
File "C:\Python27\lib\multiprocessing\forking.py", line 358, in get_command_li
ne
is not going to be frozen to produce a Windows executable.''')
RuntimeError:
Attempt to start a new process before the current process
has finished its bootstrapping phase.
This probably means that you are on Windows and you have
forgotten to use the proper idiom in the main module:
if __name__ == '__main__':
freeze_support()
...
The "freeze_support()" line can be omitted if the program
is not going to be frozen to produce a Windows executable.
Muss if __name__ == '__main__' im Programm enthalten sein, um freeze_support zu nutzen?
Habe den freeze_support() Befehl mal direkt vor
Code: Alles auswählen
multiprocessing.freeze_support()
pool = multiprocessing.Pool()
Das hat jetzt keine Abhilfe geschaffen, die Fehlermeldung taucht weiterhin auf.
Zuversichtlich stimmt mich jetzt aber: Wenn ich den Prozessverlauf im Taskmanager anschaue bleibts aber jetzt schon bei den maximal 7 Aufrufen und die Prozesse verschwinden nach der Ausführung, also keine Endlosschleife mehr.
Was könnte ich noch ändern?
@hera: Da Du cxfreeze ja gar nicht benutzt, sollte das mit dem Freeze-Support nicht nötig sein. ``if __name__ == '__main__':`` muss im Grunde schon vorhanden sein, oder wie stellst Du sonst sicher, dass das Modul mit dem das Programm gestartet wird, ohne Seiteneffekte importiert werden kann?
habe nun __name__ == '__main__' mit aufgenommen und erhalte diese Meldung:
Ich weiss nicht, wie ich Seiteneffekte vermeiden kann...
Code: Alles auswählen
C:\myProg>"C:\myProg\program_control.py"
Exception in thread Thread-2:
Traceback (most recent call last):
File "C:\Python27\lib\threading.py", line 808, in __bootstrap_inner
self.run()
File "C:\Python27\lib\threading.py", line 761, in run
self.__target(*self.__args, **self.__kwargs)
File "C:\Python27\lib\multiprocessing\pool.py", line 342, in _handle_tasks
put(task)
PicklingError: Can't pickle <type 'function'>: attribute lookup __builtin__.func
tion failed
@hera: Vielleicht sollte man das von beiden Seiten angehen. Also nicht nur Deinen Code mit `multiprocessing` zum Laufen bringen, sondern erst einmal `multiprocessing` mit einem minimalen Beispiel zum Laufen bringen:
Die Seiteneffekte verhinderst Du durch die ``if``-Abfrage. Du kannst das Modul importieren ohne das der Code in dem ``if``-Block ausgeführt wird.
Zu der neuen Fehlermeldung: Offensichtlich versuchst Du irgendetwas zu verwenden was sich nicht mit `pickle` serialisieren lässt. Also bekommt man das auch nicht in den anderen Prozess. Ich hatte ja schon Zweifel angemeldet ob man als erstes Argument in diesem Fall überhaupt eine Methode verwenden kann. Anonyme Funktionen funktionieren auch nicht — die führen zum Beispiel genau zu der angegebenen Ausnahme.
Code: Alles auswählen
from multiprocessing import Pool
from time import sleep
def do_something(value):
sleep(0.5)
return value * 2
def main():
pool = Pool()
print pool.map(do_something, range(10))
if __name__ == '__main__':
main()
Zu der neuen Fehlermeldung: Offensichtlich versuchst Du irgendetwas zu verwenden was sich nicht mit `pickle` serialisieren lässt. Also bekommt man das auch nicht in den anderen Prozess. Ich hatte ja schon Zweifel angemeldet ob man als erstes Argument in diesem Fall überhaupt eine Methode verwenden kann. Anonyme Funktionen funktionieren auch nicht — die führen zum Beispiel genau zu der angegebenen Ausnahme.
@BlackJack:
ein Minimalbeispiel läuft, das habe ich schon mit dem Code versucht, der früher mal gepostet wurde.
Deshalb wird es wohl Punkt 2 sein, dass ich versuche was zu serialisieren, was sich nicht serialisieren lässt. Da ich nicht genau weiß, was sich serialisierne lässt, beschreibe ich mal, was ich aufrufe (hier erst nochmal die Funktion von weiter vorne in den Forenbeiträgen.
ein Minimalbeispiel läuft, das habe ich schon mit dem Code versucht, der früher mal gepostet wurde.
Deshalb wird es wohl Punkt 2 sein, dass ich versuche was zu serialisieren, was sich nicht serialisieren lässt. Da ich nicht genau weiß, was sich serialisierne lässt, beschreibe ich mal, was ich aufrufe (hier erst nochmal die Funktion von weiter vorne in den Forenbeiträgen.
ESPPRC ist ein Modul mit der Funktion solve_Problem(.). Es handelt sich also nicht um ein instanziiertes Objekt einer Klasse. Heisst das, das ich diese Funktion solve_Problem(.) nicht serialisieren kann? Oder liegt es an der anonymen Funktion lambda?Code: Alles auswählen
def solve_KW(self): LABE_aller_perioden = [] pool = Pool() for result in pool.map( lambda p: ESPPRC.solve_Problem(self.MP_for_CG, p, self.instanz, self.node_id, self.iteration, self.arcs_to_forbid, self.max_labels_to_create), Node.periods_SP ): LABE_aller_perioden.extend( self.delete_doppelte_variable_in_sol_array(result, self.MP_for_CG)) return LABE_aller_perioden
@hera: Es liegt am ``lambda``. Funktionen werden einfach nur als der vollständige „Pfad” zu der Funktion serialisiert, also alle Paketnamen, plus der Modulname, plus der Name der Funktion. Und beim deserialisieren werden diese Informationen verwendet um die Funktion aus dem Modul zu importieren. Mal so als Beispiel:
Code: Alles auswählen
In [1]: import pickle
In [2]: from xml.etree import ElementTree as etree
In [3]: print pickle.dumps(etree.parse)
cxml.etree.ElementTree
parse
p0
.
@BlackJack:
den code habe ich jetzt wie folgt umgebaut:
Die Funktion über die serializiert werden soll ESPPRC.solve_Problem habe ich in eine Funktion f gesteckt mit nur einem Parameter p. Grund hierfür ist, dass mir nicht klar war, wie ich map() sonst mitteilen soll, dass es ja nur einen Laufvariable gibt über die iteriert werden soll nach Wegfall von lambda.
Aufruf von f im Hauptprogramm sieht jetzt so aus:
Die Fehlermeldung gibts leider immer noch:
Siehst Du noch was, was sich in diesem Aufruf nicht serialisieren lässt neben lambda?
den code habe ich jetzt wie folgt umgebaut:
Code: Alles auswählen
def f(self, p):
LABE_aller_perioden = []
result = ESPPRC.solve_Problem(self.MP_for_CG, p,
self.instanz,
self.node_id, self.iteration,
self.arcs_to_forbid,
Node.max_labels_to_create)
LABE_aller_perioden.extend(
self.delete_doppelte_variable_in_sol_array(result, self.MP_for_CG))
return LABE_aller_perioden
Aufruf von f im Hauptprogramm sieht jetzt so aus:
Code: Alles auswählen
pool = multiprocessing.Pool()
print(pool.map(self.f, Node.periods_SP))
Code: Alles auswählen
Exception in thread Thread-2:
Traceback (most recent call last):
File "C:\Python27\lib\threading.py", line 808, in __bootstrap_inner
self.run()
File "C:\Python27\lib\threading.py", line 761, in run
self.__target(*self.__args, **self.__kwargs)
File "C:\Python27\lib\multiprocessing\pool.py", line 342, in _handle_tasks
put(task)
PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin_
_.instancemethod failed
@hera: Naja `f` lässt sich nicht serialisieren, denn das ist ja eine Methode auf einem Objekt das zur Laufzeit irgendwie erzeugt wurde, und *wie* das erzeugt wurde, kann der Prozess auf der anderen Seite ja nicht nachvollziehen.
@BlackJack:
Das heißt: f(.) aus dem Objekt rausnehmen, in ein separates Modul schreiben und dann aus dem Modul heraus und nicht aus dem Objekt heraus aufrufen?
aber halt, wie komme ich denn dann an die Parameter aus dem Objekt ran, die mit "self" aufgerufen werden?!
Das heißt: f(.) aus dem Objekt rausnehmen, in ein separates Modul schreiben und dann aus dem Modul heraus und nicht aus dem Objekt heraus aufrufen?
aber halt, wie komme ich denn dann an die Parameter aus dem Objekt ran, die mit "self" aufgerufen werden?!
Zuletzt geändert von hera am Sonntag 21. Juli 2013, 17:24, insgesamt 1-mal geändert.
@hera: Ein separates Modul muss es nicht sein, aber halt eine Funktion die man importieren kann. Und zwar eine die ein Argument bekommt, welches alle Informationen für den Aufruf enthält. Also zum Beispiel ein Tupel mit `p` und dem Objekt wo die ganzen Attribute drauf sind:
Aufruf dann mit:
Falls an dem Objekt mit der `solve_KW()`-Methode deutlich mehr Daten hängen als von der `solve()`-Funktion benötigt werden, sollte man natürlich nicht das Objekt übergeben, sondern die einzelnen benötigten Attribute einzeln. Das muss ja alles serialisiert und an den Arbeiterprozess geschickt werden. Sollten dass dann immer noch zu viele Daten sein, die sich ja von Aufruf zu Aufruf nicht ändern, könnte man die beim erzeugen des Pools an den Arbeiterprozess übertragen und zum Beispiel dort an das aktuelle Prozessobjekt binden (`multiprocessing.current_process()`) und dann nur noch `p` bei dem Aufrufen übertragen.
Code: Alles auswählen
def solve((p, some_object)):
ESPPRC.solve_Problem(
some_object.MP_for_CG,
p,
some_object.instanz,
some_object.node_id,
some_object.iteration,
some_object.arcs_to_forbid,
some_object.max_labels_to_create
)
Code: Alles auswählen
def solve_KW(self):
LABE_aller_perioden = []
pool = Pool()
for result in pool.map(solve, [(p, self) for p in Node.periods_SP], 1):
LABE_aller_perioden.extend(
self.delete_doppelte_variable_in_sol_array(
result, self.MP_for_CG
)
)
return LABE_aller_perioden
Wenn es *nur* die Parameter sind und dies keine Methodenaufrufe auf dem Objekt umfasst, dann kannst du diese Parameter als Dictionary übergeben. Die zu mappende Methode nimmt dann dieses Dictionary als Argument an und fragt die einzelnen Werte nach Bedarf ab.hera hat geschrieben:aber halt, wie komme ich denn dann an die Parameter aus dem Objekt ran, die mit "self" aufgerufen werden?!
Hier ein Beispiel zur Erzeugung eines solchen Dictionaries:
Code: Alles auswählen
>>> class MyObj(object):
... def __init__(self, foo, bar, baz):
... self.foo = foo
... self.bar = bar
... self.baz = baz
...
>>> obj = MyObj('spam', 'ham', 'egg')
>>> attrs = ('foo', 'bar', 'baz')
>>> dict((name, getattr(obj, name)) for name in attrs)
{'baz': 'egg', 'foo': 'spam', 'bar': 'ham'}
EDIT: Oder du verwendest alternativ die Process()-Schnittstelle. Dort kann man mehrere Argumente übergeben (was in deinem Fall die entsprechenden Attribute wären). Dieser Weg ist allerdings für das Ablaufen der zu bearbeitenden Daten nicht so komfortabel wie `map()`. Ich würde wohl eher letzteres nehmen und mir halt ein `dict` erzeugen.