6

我有一个应用程序实例化xmlrpclib.ServerProxy一次,然后将其传递给多个线程(Web 应用程序请求),它们都同时执行 XML/RPC 调用。这适用于 python 2.6。使用 python 2.7,一旦我们处于多线程环境中,我们就会遇到很多错误(ResponseNotReady, )。CannotSendRequest

# This code works well in python 2.6, and breaks in python 2.7.

import xmlrpclib
import thread

proxy = xmlrpclib.ServerProxy("http://localhost:5000/")

def fetch_users():
  print proxy.getUsers()

for _ in range(10):
  thread.start_new_thread(fetch_users, ())

while(1):
  pass

这里有什么问题,是否有一种线程安全的方式来重用 ServerProxy 对象?

4

2 回答 2

5

我们找到了问题的原因:在 python 2.6 中,每个 XML/RPC 方法调用都会创建一个 TCP 连接。另一方面,Python 2.7 为每个 ServerProxy 对象打开一个 TCP 连接,并保持打开状态(使用支持的服务器keep-alive)。此外,该类不是线程安全的,因此并发请求可能会相互干扰。

显然,2.6 版本隐含地是线程安全的,因为 TCP 连接不会被重用,并且所有特定于连接的数据似乎都保存在非共享堆栈变量中。

所以可能的解决方案是:

  1. ServerProxy为每个线程创建一个对象(并隐式打开一个 TCP 连接)
  2. 锁定对单个共享ServerProxy对象的访问
  3. 实现请求队列
于 2014-08-28T12:38:24.877 回答
0

大多数代码不是线程安全的。但是我不知道为什么代码会在 2.6 中工作,但会在 2.7 中引发错误。

这是对这个问题的另一种看法:

  • 使用更高级别的threading模块

  • 代理是每个线程的,而不是全局的。这样更安全,因此线程不会通过覆盖共享的全局对象而相互混淆。

  • 线程join()在最后被显式编辑,以确保它们都完成

资源

import xmlrpclib
import threading

def fetch_users():
    proxy = xmlrpclib.ServerProxy("http://localhost:5000/")
    print proxy.getUsers()

for _ in range(10):
  threading.Thread(target=fetch_users, args=()).start()

# wait for all threads to exit
for th in threading.enumerate():
    th.join()
于 2014-08-27T17:11:37.253 回答