QThreads和xmlrpc客户端

时间:2012-03-13 20:51:35

标签: python multithreading pyqt pyside xmlrpclib

我正在尝试使用许多QThreads中的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 %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()

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

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

当只使用一个Thread时可以正常工作:

$ 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

1 个答案:

答案 0 :(得分:2)

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

我还删除了你的旋转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 %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()

更新

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

奇怪的是,在OSX上的python 2.6 / 2.7或linux下的python 2.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()