Question

J'essaie d'utiliser le client XMLRPC à partir de nombreuses QThreads.Pour vous assurer qu'un seul thread utilise le client XMLRPC, j'ai créé la serrure avec Qmutex.Mon code:

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()

Mais ça ne marche pas et je ne sais pas pourquoi.Voici la sortie:

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

Lorsque vous utilisez un seul thread fonctionne 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

Lorsque vous utilisez deux instances différentes de MM fonctionnent également 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

Était-ce utile?

La solution

Il y avait quelques problèmes que j'ai vu avec le code, mais surtout celui que j'avais tout de suite que vous commencez à démarrer le client avant que le serveur n'était prêt. Lorsque j'ai d'abord instancié le serveur, alors le client, j'ai arrêté d'obtenir des erreurs de connexion.

J'ai également supprimé votre filage pendant la boucle et j'ai plutôt commencé la boucle d'événement Pyqt. De plus, vous n'abandonnez pas vraiment votre instance mm à votre classe de demande (pas que cela importait beaucoup pour cet exemple puisque vous utilisiez la même instance).

Quoi qu'il en soit, voici ma version qui semble fonctionner:

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()

Mise à jour

Après avoir examiné cela un peu plus, j'ai réalisé que c'est un bogue dans Python 2.7 et XMLRPC, où ils ont changé comment cela crée des connexions. http://bugs.python.org/issue6907

Étrangement, ce code ne plante pas pour moi sur Python 2.6 / 2.7 sur OSX ou sur Python 2.6 sous Linux. Mais cela me bloque avec Python 2.7 sous Linux.

Lorsque j'ai déplacé le mécanisme de verrouillage en dehors de l'instance MM, il semblait commencer à travailler sous 2,7 sous 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()

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top