multiprocessing & HTTPConnection

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Boa
User
Beiträge: 190
Registriert: Sonntag 25. Januar 2009, 12:34

Hi,

Ich versuche eine Funktion zu schreiben, die einen HTTP Download mit einem Timeout kombiniert. Dabei sollen außerdem die Verbindungen gecached werden. Die Lösung mit eventlet habe ich fürs erste aufgegeben, weil ich die Fehlermeldungen nicht deuten konnte, die ich in meinem Programm bekam. Nun versuche ich es erst Mal mit multiprocessing, auch wenn es nicht so schön ist.
Beim Zuweisen einer HTTPConnection an mein multiprocessing dict bekomme ich bei mir einen Fehler:
PicklingError: Can't pickle httplib.HTTPConnection: it's not the same object as httplib.HTTPConnection
Ich habe versucht das Problem nachzustellen, bekomme dabei aber noch einen anderen Fehler mit dem ich nichts anfangen kann:

Code: Alles auswählen

import httplib
from multiprocessing import Manager
from multiprocessing import Process
manager = Manager()
conn_pool = manager.dict()
def f():
    conn_pool[1]=httplib.HTTPConnection("www.google.de")

p = Process(target=f, args=())
p.start()

Code: Alles auswählen

Process Process-2:
Traceback (most recent call last):
  File "/usr/lib/python2.6/multiprocessing/process.py", line 232, in _bootstrap
    self.run()
  File "/usr/lib/python2.6/multiprocessing/process.py", line 88, in run
    self._target(*self._args, **self._kwargs)
  File "test.py", line 10, in f
    conn_pool[1]=httplib.HTTPConnection("www.google.de")
  File "<string>", line 2, in __setitem__
  File "/usr/lib/python2.6/multiprocessing/managers.py", line 722, in _callmethod
    self._connect()
  File "/usr/lib/python2.6/multiprocessing/managers.py", line 709, in _connect
    conn = self._Client(self._token.address, authkey=self._authkey)
  File "/usr/lib/python2.6/multiprocessing/connection.py", line 149, in Client
    answer_challenge(c, authkey)
  File "/usr/lib/python2.6/multiprocessing/connection.py", line 383, in answer_challenge
    message = connection.recv_bytes(256)         # reject large message
EOFError
Vielleicht kennt ihr eine Lösung oder könnt mir einen Tipp geben.

Thx,
Boa
Boa
User
Beiträge: 190
Registriert: Sonntag 25. Januar 2009, 12:34

Hmm, ich denke ich werde die Verbindungen einfach in ein shelve o.ä. packen um sie zwischen den Prozessen auszutauschen. Mit httplib2 hat es übrigens auch nicht geklappt.
BlackJack

@Boa: Du kannst so etwas wie eine Netzwerkverbindung nicht serialisieren. Da hängen Zustandsinformationen mit zusammen die Du vom Betriebssystem gar nicht in die Finger bekommst und die man deshalb auch gar nicht wieder herstellen könnte wenn man die Verbindung deserialisiert.
Boa
User
Beiträge: 190
Registriert: Sonntag 25. Januar 2009, 12:34

BlackJack hat geschrieben:@Boa: Du kannst so etwas wie eine Netzwerkverbindung nicht serialisieren. Da hängen Zustandsinformationen mit zusammen die Du vom Betriebssystem gar nicht in die Finger bekommst und die man deshalb auch gar nicht wieder herstellen könnte wenn man die Verbindung deserialisiert.
Was genau lässt sich bei dem Socket nicht serialisieren? Unter Linux sind Sockets soweit ich weiß doch nur spezielle Dateien. Mit pickle habe ich bisher auch keine Probleme festgestellt.
BlackJack

@Boa: Tja und Dateiobjekte kann man auch nicht serialisieren. ;-)

Code: Alles auswählen

In [1]: import pickle

In [2]: f = open('test.py')

In [3]: pickle.dumps(f)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-03b30dfeb586> in <module>()
----> 1 pickle.dumps(f)

/usr/lib/python2.7/pickle.pyc in dumps(obj, protocol)
   1372 def dumps(obj, protocol=None):
   1373     file = StringIO()
-> 1374     Pickler(file, protocol).dump(obj)
   1375     return file.getvalue()
   1376 

/usr/lib/python2.7/pickle.pyc in dump(self, obj)
    222         if self.proto >= 2:
    223             self.write(PROTO + chr(self.proto))
--> 224         self.save(obj)
    225         self.write(STOP)
    226 

/usr/lib/python2.7/pickle.pyc in save(self, obj)
    304             reduce = getattr(obj, "__reduce_ex__", None)
    305             if reduce:
--> 306                 rv = reduce(self.proto)
    307             else:
    308                 reduce = getattr(obj, "__reduce__", None)

/usr/lib/python2.7/copy_reg.pyc in _reduce_ex(self, proto)
     68     else:
     69         if base is self.__class__:
---> 70             raise TypeError, "can't pickle %s objects" % base.__name__
     71         state = base(self)
     72     args = (self.__class__, base, state)

TypeError: can't pickle file objects
Du bekommst von Dateien als Programmierer letztendlich immer nur eine Zahl oder einen opaken Zeiger in die Hand. Alle anderen Informationen die zu einer offenen Datei gehören, kennt nur das Betriebsystem. Dazu kommt noch das diese Zahl nur innerhalb eines Prozesses gültig ist. Zwei verschiedene Prozesse können die gleiche Zahl vom Betriebssystem bekommen, die steht aber jeweils für eine andere Datei. Deshalb kann man diese Zahl auch nicht einfach an einen anderen Prozess weitergeben.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Boa hat geschrieben:Dabei sollen außerdem die Verbindungen gecached werden
Was erhoffst du dir von diesem Vorgehen?
Boa
User
Beiträge: 190
Registriert: Sonntag 25. Januar 2009, 12:34

Also mit Pickle ließ sich httplib.HTTPConnection serialisieren. Bleibt noch die Frage ob das tatsächlich die Verbindung aufrecht erhält.
@snafu: Geschwindigkeit bei vielen Anfragen - dazu gibt es ja den Connection: keep-alive header

ot:
@BlackJack: Im Prinzip funktioniert das: stackoverflow.com/questions/1075443/share-objects-with-file-handle-attribute-between-processes
Sockets kann man auch weitergeben: http://www.normalesup.org/~george/comp/libancillary/
BlackJack

@Boa: Also ich kann keine *bestehende* Verbindung serialisieren, nur unverbundene `HTTPConnection`\s:

Code: Alles auswählen

In [12]: c = httplib.HTTPConnection('www.python-forum.de')

In [13]: x = pickle.dumps(c)  # Geht.

In [14]: c.connect()

In [15]: pickle.dumps(c)  # Geht nicht mehr.
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-15-49ce1ecf77bc> in <module>()
----> 1 pickle.dumps(c)

/usr/lib/python2.7/pickle.pyc in dumps(obj, protocol)
   1372 def dumps(obj, protocol=None):
   1373     file = StringIO()
-> 1374     Pickler(file, protocol).dump(obj)
   1375     return file.getvalue()
   1376 

/usr/lib/python2.7/pickle.pyc in dump(self, obj)
    222         if self.proto >= 2:
    223             self.write(PROTO + chr(self.proto))
--> 224         self.save(obj)
    225         self.write(STOP)
    226 

/usr/lib/python2.7/pickle.pyc in save(self, obj)
    284         f = self.dispatch.get(t)
    285         if f:
--> 286             f(self, obj) # Call unbound method with explicit self
    287             return
    288 

/usr/lib/python2.7/pickle.pyc in save_inst(self, obj)
    723             stuff = getstate()
    724             _keep_alive(stuff, memo)
--> 725         save(stuff)
    726         write(BUILD)
    727 

/usr/lib/python2.7/pickle.pyc in save(self, obj)
    284         f = self.dispatch.get(t)
    285         if f:
--> 286             f(self, obj) # Call unbound method with explicit self
    287             return
    288 

/usr/lib/python2.7/pickle.pyc in save_dict(self, obj)
    647 
    648         self.memoize(obj)
--> 649         self._batch_setitems(obj.iteritems())
    650 
    651     dispatch[DictionaryType] = save_dict

/usr/lib/python2.7/pickle.pyc in _batch_setitems(self, items)
    661             for k, v in items:
    662                 save(k)
--> 663                 save(v)
    664                 write(SETITEM)
    665             return

/usr/lib/python2.7/pickle.pyc in save(self, obj)
    304             reduce = getattr(obj, "__reduce_ex__", None)
    305             if reduce:
--> 306                 rv = reduce(self.proto)
    307             else:
    308                 reduce = getattr(obj, "__reduce__", None)

/usr/lib/python2.7/copy_reg.pyc in _reduce_ex(self, proto)
     75     except AttributeError:
     76         if getattr(self, "__slots__", None):
---> 77             raise TypeError("a class that defines __slots__ without "
     78                             "defining __getstate__ cannot be pickled")
     79         try:

TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled
Boa
User
Beiträge: 190
Registriert: Sonntag 25. Januar 2009, 12:34

BlackJack hat geschrieben:@Boa: Also ich kann keine *bestehende* Verbindung serialisieren, nur unverbundene `HTTPConnection`\s:
Ah Danke, gut zu wissen. Dann lasse ich das sein.
Antworten