Pregunta

Estoy tratando de usar el cliente XMLRPC de muchos QThreads.Para asegurarse de que solo un hilo esté usando el cliente XMLRPC, creé bloqueo con QMUTEX.Mi código:

import sys
import xmlrpclib
import threading
import time

from SimpleXMLRPCServer import SimpleXMLRPCServer

from PyQt4 import QtCore, QtGui

class MM(object):
    def __init__(self):
        self.lock = QtCore.QMutex()
        self.xmlrpc_client = xmlrpclib.ServerProxy('http://localhost:9092')

    def __getattr__(self, name):
        self.lock.lock()
        sys.stderr.write('locked, for %s\n' % name)
        print threading.current_thread()
        result = self.xmlrpc_client.__getattr__(name)
        sys.stderr.write('unlocked by %s\n' % name)
        self.lock.unlock()
        return result

class Server(QtCore.QThread):
    def __init__(self):
        QtCore.QThread.__init__(self)
        self.server = None

    def run(self):
        self.server = SimpleXMLRPCServer(("localhost", 9092), logRequests = False)
        def one():
            return 1
        self.server.register_function(one, 'one')
        self.server.serve_forever()
        print "SERVER DONE"


class Ask(QtCore.QThread):
    def __init__(self, mmInst):
        QtCore.QThread.__init__(self)
        self.mm = mmInst
        self._stopping = False

    def run(self):
        while not self._stopping:
            time.sleep(0.5)
            print self.mm.one()

    def stop(self):
        self._stopping = True
        self.wait()


def start_gui():
    app = QtGui.QApplication(sys.argv)

    server = Server()
    server.start()

    time.sleep(1)

    mm = MM()
    print mm.one()

    a1 = Ask(mm)
    a1.start()

    a2 = Ask(mm)
    a2.start()

    try:
        app.exec_()
    except KeyboardInterrupt:
        server.server.shutdown()

if __name__ == "__main__":
    start_gui()

Pero no funciona y no estoy seguro de por qué.Aquí está la salida:

locked, for one
<_MainThread(MainThread, started 1648)>
unlocked by one
1
locked, for one
<_DummyThread(Dummy-1, started daemon 356)>
unlocked by one
locked, for one
<_DummyThread(Dummy-2, started daemon 1480)>
unlocked by one
Traceback (most recent call last):
  File "H:\poker\repos\TestSuite\test.py", line 46, in run
    print self.mm.one()
  File "C:\Python27\lib\xmlrpclib.py", line 1224, in __call__
    return self.__send(self.__name, args)
  File "C:\Python27\lib\xmlrpclib.py", line 1575, in __request
    verbose=self.__verbose
  File "C:\Python27\lib\xmlrpclib.py", line 1264, in request
    return self.single_request(host, handler, request_body, verbose)
  File "C:\Python27\lib\xmlrpclib.py", line 1289, in single_request
    self.send_request(h, handler, request_body)
  File "C:\Python27\lib\xmlrpclib.py", line 1391, in send_request
    connection.putrequest("POST", handler, skip_accept_encoding=True)
  File "C:\Python27\lib\httplib.py", line 853, in putrequest
    raise CannotSendRequest()
httplib.CannotSendRequest
Traceback (most recent call last):
  File "H:\poker\repos\TestSuite\test.py", line 46, in run
    print self.mm.one()
  File "C:\Python27\lib\xmlrpclib.py", line 1224, in __call__
    return self.__send(self.__name, args)
  File "C:\Python27\lib\xmlrpclib.py", line 1575, in __request
    verbose=self.__verbose
  File "C:\Python27\lib\xmlrpclib.py", line 1264, in request
    return self.single_request(host, handler, request_body, verbose)
  File "C:\Python27\lib\xmlrpclib.py", line 1294, in single_request
    response = h.getresponse(buffering=True)
  File "C:\Python27\lib\httplib.py", line 1015, in getresponse
    raise ResponseNotReady()
httplib.ResponseNotReady

Cuando se usa solo un hilo funciona bien:

$ diff -u test.py.back test.py
--- test.py.back        2012-03-14 01:34:37.666425000 +0100
+++ test.py     2012-03-14 01:33:01.423265000 +0100
@@ -63,8 +63,8 @@
     a1 = Ask(mm)
     a1.start()

-    a2 = Ask(mm)
-    a2.start()
+    #a2 = Ask(mm)
+    #a2.start()

     try:
         app.exec_()
$ python test.py
locked, for one
<_MainThread(MainThread, started -1219930432)>
unlocked by one
1
locked, for one
<_DummyThread(Dummy-1, started daemon -1287918736)>
unlocked by one
1
locked, for one
<_DummyThread(Dummy-1, started daemon -1287918736)>
unlocked by one
1
locked, for one
<_DummyThread(Dummy-1, started daemon -1287918736)>
unlocked by one
1

Cuando use dos instancias diferentes de MM también funciona bien:

$ diff -u test.py.back test.py
--- test.py.back        2012-03-14 01:34:37.666425000 +0100
+++ test.py     2012-03-14 01:38:47.352862000 +0100
@@ -57,13 +57,13 @@

     time.sleep(1)

-    mm = MM()
-    print mm.one()
+    #mm = MM()
+    #print mm.one()

-    a1 = Ask(mm)
+    a1 = Ask(MM())
     a1.start()

-    a2 = Ask(mm)
+    a2 = Ask(MM())
     a2.start()

     try:
adam@sabayon /media/Nowy/poker/repos/TestSuite $ python test.py
locked, for one
locked, for one
<_DummyThread(Dummy-1, started daemon -1288275088)><_DummyThread(Dummy-2, started daemon -1298138256)>
unlocked by one

unlocked by one
11

locked, for one
<_DummyThread(Dummy-2, started daemon -1298138256)>
unlocked by one
locked, for one
<_DummyThread(Dummy-1, started daemon -1288275088)>
unlocked by one
1
1
locked, for one
<_DummyThread(Dummy-1, started daemon -1288275088)>
unlocked by one
locked, for one
1<_DummyThread(Dummy-2, started daemon -1298138256)>

unlocked by one
1

¿Fue útil?

Solución

Hubo un par de problemas que vi con el código, pero principalmente el que estaba de inmediato fue que estabas comenzando el cliente antes de que el servidor estuviera listo. Cuando instancié primero al servidor, entonces el cliente, dejé de obtener errores de conexión.

También me eliminé su giro mientras el bucle y, en su lugar, solo inició el bucle de eventos PYQT. Además, no presenta realmente la instancia de MM a su clase de Preguntar (no es que importara mucho para este ejemplo, ya que estaba usando la misma instancia).

De todos modos, aquí está mi versión que parece funcionar:

import sys
import xmlrpclib
import threading
import time

from SimpleXMLRPCServer import SimpleXMLRPCServer

from PyQt4 import QtCore, QtGui

class MM(object):
    def __init__(self):
        self.lock = QtCore.QMutex()
        self.xmlrpc_client = xmlrpclib.ServerProxy('http://localhost:9092')

    def __getattr__(self, name):
        self.lock.lock()
        sys.stderr.write('locked, for %s\n' % name)
        print threading.current_thread()
        result = self.xmlrpc_client.__getattr__(name)
        sys.stderr.write('unlocked by %s\n' % name)
        self.lock.unlock()
        return result

class Server(QtCore.QThread):
    def __init__(self):
        QtCore.QThread.__init__(self)
        self.server = None

    def run(self):
        self.server = SimpleXMLRPCServer(("localhost", 9092), logRequests = False)
        def one():
            return 1
        self.server.register_function(one, 'one')
        self.server.serve_forever()
        print "SERVER DONE"


class Ask(QtCore.QThread):
    def __init__(self, mmInst):
        QtCore.QThread.__init__(self)
        self.mm = mmInst
        self._stopping = False

    def run(self):
        while not self._stopping:
            time.sleep(0.5)
            print self.mm.one()

    def stop(self):
        self._stopping = True
        self.wait()


def start_gui():
    app = QtGui.QApplication(sys.argv)

    server = Server()
    server.start()

    time.sleep(.25)

    mm = MM()
    print mm.one()

    a1 = Ask(mm)
    a1.start()

    a2 = Ask(mm)
    a2.start()

    try:
        app.exec_()
    except KeyboardInterrupt:
        server.server.shutdown()


if __name__ == "__main__":
    start_gui()

Actualización

Después de mirar esto un poco más, me di cuenta de que es un error en Python 2.7 y XMLRPC, donde cambiaron cómo crea conexiones. http://bugs.python.org/issuen6907

Extrañamente, este código no se bloquea por mí en Python 2.6 / 2.7 en OSX, o en Python 2.6 bajo Linux. Pero se estrelló por mí con Python 2.7 bajo Linux.

Cuando moví el mecanismo de bloqueo fuera de la instancia MM, parecía comenzar a funcionar bajo 2.7 en Linux:

class MM(object):
    def __init__(self):
        self.xmlrpc_client = xmlrpclib.ServerProxy('http://localhost:9093')

    def __getattr__(self, name):
        return self.xmlrpc_client.__getattr__(name)


class Ask(QtCore.QThread):
    def __init__(self, mmInst, lock):
        QtCore.QThread.__init__(self)
        self.mm = mmInst
        self.lock = lock

    def run(self):
        while not self._stopping:
            time.sleep(0.5)
            self.lock.lock()
            print self.mm.one()
            self.lock.unlock()

def start_gui():
    app = QtGui.QApplication(sys.argv)

    ...

    lock = QtCore.QMutex()

    a1 = Ask(mm, lock)
    a1.start()

    a2 = Ask(mm, lock)
    a2.start()

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top