QThreads和xmlrpc客户端



我正在尝试从许多QThread中使用xmlrpc客户端。为了确保只有一个线程使用xmlrpc客户端,我使用QMutex创建了锁。我的代码:

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 %sn' % name)
        print threading.current_thread()
        result = self.xmlrpc_client.__getattr__(name)
        sys.stderr.write('unlocked by %sn' % 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()

但它不起作用,我不知道为什么。输出如下:

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:pokerreposTestSuitetest.py", line 46, in run
    print self.mm.one()
  File "C:Python27libxmlrpclib.py", line 1224, in __call__
    return self.__send(self.__name, args)
  File "C:Python27libxmlrpclib.py", line 1575, in __request
    verbose=self.__verbose
  File "C:Python27libxmlrpclib.py", line 1264, in request
    return self.single_request(host, handler, request_body, verbose)
  File "C:Python27libxmlrpclib.py", line 1289, in single_request
    self.send_request(h, handler, request_body)
  File "C:Python27libxmlrpclib.py", line 1391, in send_request
    connection.putrequest("POST", handler, skip_accept_encoding=True)
  File "C:Python27libhttplib.py", line 853, in putrequest
    raise CannotSendRequest()
httplib.CannotSendRequest
Traceback (most recent call last):
  File "H:pokerreposTestSuitetest.py", line 46, in run
    print self.mm.one()
  File "C:Python27libxmlrpclib.py", line 1224, in __call__
    return self.__send(self.__name, args)
  File "C:Python27libxmlrpclib.py", line 1575, in __request
    verbose=self.__verbose
  File "C:Python27libxmlrpclib.py", line 1264, in request
    return self.single_request(host, handler, request_body, verbose)
  File "C:Python27libxmlrpclib.py", line 1294, in single_request
    response = h.getresponse(buffering=True)
  File "C:Python27libhttplib.py", line 1015, in getresponse
    raise ResponseNotReady()
httplib.ResponseNotReady

当只使用一个线程时效果良好:

$ 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

当使用MM的两个不同实例时也可以正常工作:

$ 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

我在代码中看到了一些问题,但我马上得到的主要问题是,您在服务器准备好之前启动了客户端。当我先实例化服务器,然后实例化客户端时,我不再出现连接错误。

我还删除了您的spinning while循环,而只是启动pyqt事件循环。此外,您并没有真正将MM实例传递给Ask类(因为您使用的是同一个实例,所以这对本例来说并不重要)。

不管怎样,这是我的版本,它似乎起作用:

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 %sn' % name)
        print threading.current_thread()
        result = self.xmlrpc_client.__getattr__(name)
        sys.stderr.write('unlocked by %sn' % 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()

更新

在进一步研究之后,我意识到这是python2.7和xmlrpc中的一个错误,他们改变了它创建连接的方式。http://bugs.python.org/issue6907

奇怪的是,这段代码在OSX上的python2.6/2.7或linux下的python2.6上都不会崩溃。但对我来说,在linux下使用python 2.7确实会崩溃。

当我将锁定机制移到MM实例之外时,它似乎在linux上的2.7下开始工作:

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

最新更新