Seite 1 von 1

Multiprocessing und der Pickle-Error

Verfasst: Dienstag 13. September 2011, 13:07
von pyme
Hallo zusammen,
ich bin Python Neuling und versuche mich gerade an einem multiprozess basierten Programm. Leider bekomme ich das noch nicht so ganz hin, habe derzeit immer Pickle Errors. So wie ich das verstehe bekommt man die doch nur dann wenn man einen Datentyp verwendet der von Pickle nicht serialisiert werden kann. Aber meine Argumente bestehen aus einem Dictionary und einem String, welche ich auch ohne Probleme mit pickle.dump serialisieren kann.

Bin leider etwas ratlos, und weiß nich wo mein Problem liegt bzw. geschweige denn wie ich es behebe. Das Traceback sieht wie folgt aus:

Code: Alles auswählen

Traceback (most recent call last):
  File "D:\eclipse_workspace_peanuts\qwert\src\Gui\Aui\mPaneLeft.py", line 89, in start
    self.worker.start()
  File "C:\Python26\lib\multiprocessing\process.py", line 104, in start
    self._popen = Popen(self)
  File "C:\Python26\lib\multiprocessing\forking.py", line 239, in __init__
    dump(process_obj, to_child, HIGHEST_PROTOCOL)
  File "C:\Python26\lib\multiprocessing\forking.py", line 162, in dump
    ForkingPickler(file, protocol).dump(obj)
  File "C:\Python26\lib\pickle.py", line 224, in dump
    self.save(obj)
  File "C:\Python26\lib\pickle.py", line 331, in save
    self.save_reduce(obj=obj, *rv)
  File "C:\Python26\lib\pickle.py", line 419, in save_reduce
    save(state)
  File "C:\Python26\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python26\lib\pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "C:\Python26\lib\pickle.py", line 681, in _batch_setitems
    save(v)
  File "C:\Python26\lib\pickle.py", line 331, in save
    self.save_reduce(obj=obj, *rv)
  File "C:\Python26\lib\pickle.py", line 419, in save_reduce
    save(state)
  File "C:\Python26\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python26\lib\pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "C:\Python26\lib\pickle.py", line 681, in _batch_setitems
    save(v)
  File "C:\Python26\lib\pickle.py", line 331, in save
    self.save_reduce(obj=obj, *rv)
  File "C:\Python26\lib\pickle.py", line 419, in save_reduce
    save(state)
  File "C:\Python26\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python26\lib\pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "C:\Python26\lib\pickle.py", line 681, in _batch_setitems
    save(v)
  File "C:\Python26\lib\pickle.py", line 295, in save
    self.save_global(obj)
  File "C:\Python26\lib\pickle.py", line 748, in save_global
    (obj, module, name))
pickle.PicklingError: Can't pickle <class 'ctypes._FuncPtr'>: it's not found as ctypes._FuncPtr
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Python26\lib\multiprocessing\forking.py", line 342, in main
    self = load(from_parent)
  File "C:\Python26\lib\pickle.py", line 1370, in load
    return Unpickler(file).load()
  File "C:\Python26\lib\pickle.py", line 858, in load
    dispatch[key](self)
  File "C:\Python26\lib\pickle.py", line 880, in load_eof
    raise EOFError
EOFError

Re: Multiprocessing und der Pickle-Error

Verfasst: Dienstag 13. September 2011, 13:09
von Dav1d
Wieso der Fehler auftritt kann ich nicht sagen, allerdings ist das Problem bekannt, wenn du wxPython verwendest, mir ist leider auch kein Workaround bekannt

Re: Multiprocessing und der Pickle-Error

Verfasst: Dienstag 13. September 2011, 13:17
von deets
Was ist denn in dem dictionary drin?

Re: Multiprocessing und der Pickle-Error

Verfasst: Dienstag 13. September 2011, 13:22
von pyme
deets hat geschrieben:Was ist denn in dem dictionary drin?
Da sind nur Strings drin.

Re: Multiprocessing und der Pickle-Error

Verfasst: Dienstag 13. September 2011, 13:26
von Dav1d
Im IRC hat sich meine Vermutung gerade bestätigt, er verwendet wxPython .. mir war es nicht möglich multiprocessing mit wxPython zum laufen zu kriegen, woran das aber genau lag ist mir entfallen.

Re: Multiprocessing und der Pickle-Error

Verfasst: Dienstag 13. September 2011, 15:30
von pyme
Dav1d hat geschrieben:Im IRC hat sich meine Vermutung gerade bestätigt, er verwendet wxPython .. mir war es nicht möglich multiprocessing mit wxPython zum laufen zu kriegen, woran das aber genau lag ist mir entfallen.
Also falls dennoch jemand einen Ansatz für wxPython + multiprocessing hat. Er würde mich super glücklich machen.

Re: Multiprocessing und der Pickle-Error

Verfasst: Dienstag 13. September 2011, 15:45
von deets
Debug doch mal da rein, was da genau passiert - welcher key da gepickelt wird. Machst du denn was mit ctypes?

Re: Multiprocessing und der Pickle-Error

Verfasst: Dienstag 13. September 2011, 15:59
von Hyperion
Ist das jetzt eigentlich ein multiprocessing- oder ein pickle+multiprocessing-Problem? (Oder gar nur ein pickle-Problem!)

Re: Multiprocessing und der Pickle-Error

Verfasst: Dienstag 13. September 2011, 16:10
von deets
multiprocessing benutzt pickle um Argumente zu pickeln, die dann an remote prozesse uebergeben werden.

Re: Multiprocessing und der Pickle-Error

Verfasst: Dienstag 13. September 2011, 16:15
von BlackJack
@pyme: Kann man denn Deinen `self.worker` picklen?

Re: Multiprocessing und der Pickle-Error

Verfasst: Dienstag 13. September 2011, 18:21
von pyme
deets hat geschrieben:Debug doch mal da rein, was da genau passiert - welcher key da gepickelt wird. Machst du denn was mit ctypes?
Ja, in dem Worker-Objekt wird eine c-lib geladen und ctypes Objekte erstellt. Aber die Parameter die ich an das Objekt übergebe sind keine ctypes typen, die werden nur intern im Worker-Objekt erstellt und benutzt! Debuggen werde ich morgen früh und die Ergebnisse posten.
BlackJack hat geschrieben:@pyme: Kann man denn Deinen `self.worker` picklen?
Ist das denn notwendig? Dachte nur die Argumente werden gepickelt. Habe den Code gerade nicht hier, werde es gleich morgen früh probieren und Bescheid geben.

Re: Multiprocessing und der Pickle-Error

Verfasst: Dienstag 13. September 2011, 19:54
von BlackJack
@pyme: Ja das ist unter Windows notwendig:
http://docs.python.org/library/multiprocessing.html#windows hat geschrieben:Also, if you subclass Process then make sure that instances will be picklable when the Process.start() method is called.
Und die `start()`-Methode ist ja laut Traceback genau das wo's kracht. Das Problem ist ja auch ein `ctypes`-Objekt.

Re: Multiprocessing und der Pickle-Error

Verfasst: Mittwoch 14. September 2011, 08:35
von pyme
BlackJack hat geschrieben:@pyme: Ja das ist unter Windows notwendig:
http://docs.python.org/library/multiprocessing.html#windows hat geschrieben:Also, if you subclass Process then make sure that instances will be picklable when the Process.start() method is called.
Und die `start()`-Methode ist ja laut Traceback genau das wo's kracht. Das Problem ist ja auch ein `ctypes`-Objekt.
Okay, Ursache gefunden :-). Immerhin einen kleinen Schritt weiter.

Ich bin jedes Objekt in meinem Sourcecode nacheinenander durchgegangen und habe es probiert in der Shell zu picklen. Beim picklen des ctypes.CDLL Objekts ist er dann schließlich mit der gleichen Picklefehlermeldung rausgesprungen, wie er sie beim Aufruf des process.start() bringt. Hier nochmal der Traceback:

Code: Alles auswählen

Traceback (most recent call last):
  File "<pyshell#54>", line 1, in <module>
    pickle.dumps(ctypes.CDLL(r"MeineDLL.dll"))
  File "C:\Python26\lib\pickle.py", line 1366, in dumps
    Pickler(file, protocol).dump(obj)
  File "C:\Python26\lib\pickle.py", line 224, in dump
    self.save(obj)
  File "C:\Python26\lib\pickle.py", line 331, in save
    self.save_reduce(obj=obj, *rv)
  File "C:\Python26\lib\pickle.py", line 419, in save_reduce
    save(state)
  File "C:\Python26\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "C:\Python26\lib\pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "C:\Python26\lib\pickle.py", line 663, in _batch_setitems
    save(v)
  File "C:\Python26\lib\pickle.py", line 295, in save
    self.save_global(obj)
  File "C:\Python26\lib\pickle.py", line 748, in save_global
    (obj, module, name))
PicklingError: Can't pickle <class 'ctypes._FuncPtr'>: it's not found as ctypes._FuncPtr
So wie komm ich aber jetzt weiter? Muss ich dieses CDLL Objekt als shared Ctypes Object erstellen, habe dazu das hier in der Doku gefunden http://docs.python.org/library/multipro ... es-objects.

Danke für eure Hilfe bereits :-)

Re: Multiprocessing und der Pickle-Error

Verfasst: Mittwoch 14. September 2011, 09:10
von BlackJack
@pyme: Da Du wahrscheinlich nicht nur die DLL hast, sondern auch Funktionen daraus holst, also `ctypes`-Objekte hast die Zeiger auf Funktionen enthalten, wäre das vielleicht nur zufällig eine Lösung die funktioniert. Nämlich nur dann, wenn in dem anderen Prozess die gleichen Funktionen unter den gleichen Speicheradressen liegen. Ich weiss nicht ob das garantiert ist. Ich würde die DLL beziehungsweise die `ctypes`-Proxy-Objekte dafür nicht sharen, sondern in jedem Prozess neu laden/erstellen.

Mal ganz von `multiprocessing` abgesehen ist es IMHO sowieso „besser/schöner” eine DLL nicht in einem Objekt zu laden, sondern das in einem eigenen Modul zu machen. Denn man kann sowohl DLLs beziehungsweise Proxies dafür, als auch Module als Singletons ansehen.

Re: Multiprocessing und der Pickle-Error

Verfasst: Mittwoch 14. September 2011, 09:28
von pyme
BlackJack hat geschrieben:@pyme: Da Du wahrscheinlich nicht nur die DLL hast, sondern auch Funktionen daraus holst, also `ctypes`-Objekte hast die Zeiger auf Funktionen enthalten, wäre das vielleicht nur zufällig eine Lösung die funktioniert. Nämlich nur dann, wenn in dem anderen Prozess die gleichen Funktionen unter den gleichen Speicheradressen liegen. Ich weiss nicht ob das garantiert ist.
Ich dachte genau dafür benutzt man ein shared Memory. Um verschiedenen Prozessen einen gemeinsamen Addressbereich zu garantieren auf den alle zugreifen können.
BlackJack hat geschrieben:Ich würde die DLL beziehungsweise die `ctypes`-Proxy-Objekte dafür nicht sharen, sondern in jedem Prozess neu laden/erstellen.
Das fände ich auch die beste Methode, aber genau die verwende ich doch momentan erfolglos. Ich ruf ein Objekt, welches von der Klasse multiprocessing.process erbt auf. Damit sollte dieses Objekt als neuer Prozess gestartet werden. In diesem Objekt instanziiere ich die c-lib durch den aufruf ctypes.CDLL(). Aber leider kommt ja genau hier der PickleError von oben, wie soll ich das denn umgehen?
BlackJack hat geschrieben: Mal ganz von `multiprocessing` abgesehen ist es IMHO sowieso „besser/schöner” eine DLL nicht in einem Objekt zu laden, sondern das in einem eigenen Modul zu machen. Denn man kann sowohl DLLs beziehungsweise Proxies dafür, als auch Module als Singletons ansehen.
Aber würde das denn nicht genau dem widersprechen was ich vorhabe nämlich eine eigene Instanz für jeden Prozess zu erstellen? Oder habe ich da etwas falsch verstanden?

Re: Multiprocessing und der Pickle-Error

Verfasst: Mittwoch 14. September 2011, 10:05
von BlackJack
@pyme: In dem Shared Memory würdest Du ja nur die `ctypes`-Objekte ablegen, die als Proxy für die DLL dienen. Aber nicht die DLL selber. Die `ctypes`-Objekte enthalten Zeiger auf die Funktionen in der DLL. Diese Zeiger gelten aber nur für den Prozess in dem sie erstellt wurden. Du kannst den Zeiger zwar im Shared Memory ablegen, und ein anderer Prozess kann auf den Zeiger auch zugreifen, aber die Speicheradresse auf die er zeigt, kann in dem anderen Prozess eine völlig andere Bedeutung haben. Über Shared Memory kann man nur die Daten teilen, die auch tatsächlich innerhalb des Shared Memory liegen.

Das Objekt, das von `Process` erbt muss (zumindest unter Windows) komplett serialisierbar sein, weil das an den neu gestarteten Prozess übertragen wird. Und Zeiger, die auf etwas im Adressraum eines Prozesses zeigen, sind nicht serialisierbar, weil die Adresse auf die sie zeigen, nur innerhalb des laufenden Prozesses sinnvoll sind.

Prozesse haben, im Gegensatz zu Threads, jeweils einen eigenen Adressraum. Alle Exemplare von Python-Objekten in Prozessen sind neu erstellt und damit unterschiedlich. Das gilt selbst für die Shared Memory Objekte. Denn die *Python*-Objekte liegen alle im Adressraum des Prozesses und enthalten nur Zeiger auf Daten im Shared Memory.

Re: Multiprocessing und der Pickle-Error

Verfasst: Mittwoch 14. September 2011, 15:30
von pyme
Ich danke euch vielmals. Ich habe das Problem jetzt bewältigen können :-) es war tatsächlich dieses dämliche ctypes Objekt. Ich hatte leider die ganze Zeit einen Denkfehler. Ich dachte der Prozess wird bereits zu Beginn mit der Initialisierung der ProcessKlasse erzeugt. Da ich das ctypes Objekt in __init__ erzeugt habe, bin ich davon ausgegangen es wird bereits im neuen Prozess erzeugt. Jetzt hab ich den ctypes Aufruf in der run Methode und schon klappt alles :-)

Danke nochmal!