3

我正在使用 gevent wsgi 来运行一个cherrypy 应用程序,并在请求处理程序中执行一些阻塞 gevent 调用。如果我发出单个请求,阻塞调用会按预期成功并行使用一些阻塞资源(到其他进程的管道)。当我触发多个请求时出现问题,然后cherrypy返回抛出此异常的内部服务器错误:

[23/Mar/2012:17:50:35]  Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/CherryPy-3.2.2-py2.7.egg/cherrypy/_cpwsgi.py", line 170, in trap
return func(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/CherryPy-3.2.2-py2.7.egg/cherrypy/_cpwsgi.py", line 97, in __call__
return self.nextapp(environ, start_response)
  File "/usr/local/lib/python2.7/site-packages/CherryPy-3.2.2-py2.7.egg/cherrypy/_cpwsgi.py", line 385, in tail
return self.response_class(environ, start_response, self.cpapp)
  File "/usr/local/lib/python2.7/site-packages/CherryPy-3.2.2-py2.7.egg/cherrypy/_cpwsgi.py", line 232, in __init__
outstatus = r.output_status
AttributeError: 'Response' object has no attribute 'output_status'

我将问题归结为核心,以下简单的应用程序每次都会重现该问题:

import cherrypy
import gevent
from gevent import wsgi

class BugServer(object):
    @cherrypy.expose
    def index(self):
      gevent.sleep(2)
      return 'dummy foo'

if __name__ == "__main__":
        app = cherrypy.tree.mount(BugServer(), '/')
        wsgi.WSGIServer(('', 27726), app).serve_forever()

为了测试它,我使用了以下脚本,它同时触发了三个请求:

import httplib
import threading

def make_req(host):
        conn = httplib.HTTPConnection(host)
        conn.request("GET", "/")
        return conn.getresponse()

threads = []
for i in range(3):
        t = threading.Thread(target=make_req, args=('192.168.128.7:27726',), kwargs={})
        t.start()
        threads.append(t)

for t in threads:
        t.join()

我不确定是否必须深入研究cherrypy 或gevent (wsgi) 库才能找到错误。将 spawn=None 设置为 wsgi 服务器将违背使用 greenlets 来阻止请求中的资源调用的目的,并且无论如何都不起作用。

有什么建议么?谢谢。

4

2 回答 2

4

Cherrypy 使用 threading.local 作为它的 request\response 对象(如果你的 Python 版本支持它)。可以使用 gevent.monkey.patch_all 修补此对象以使用 gevent 本地存储。只需使用:

from gevent.monkey import patch_all
patch_all()

在任何导入之前(然后您甚至可以使用正常的“时间”函数而不是 gevent.time)。这在这里修复了它。

于 2012-10-11T18:25:00.923 回答
2

CherryPy 广泛使用 threadlocals,因此不适合与事件循环或其他使用同一线程处理多个请求的方法一起使用。如果您的测试同步进行调用,它可能会工作一段时间,但是一旦您尝试多个同时请求(到达速度快于处理程序返回响应的速度),您就会遇到这种错误。

应该可以cherrypy.serving用为 greenlets 或其他并行性设计的某种上下文对象替换,但迄今为止没有人花时间进行实验。

于 2012-03-23T23:27:44.080 回答