如何使CherryPy服务并发请求?

时间:2015-01-28 10:59:49

标签: python multithreading cherrypy web-frameworks

我已经读过cherrypy使用自己的线程池。但我无法看到它的优势。

假设我发出一个需要很长时间的请求,然后在另一个标签中发出请求,这将花费很短的时间。如果它确实使用多线程,则短请求应在长请求之前完成。但我看到,首先是长请求完成然后是短时间,好像所有内容都按顺序处理。

我尝试集成了不同的uWSGI框架,如Tornado和twistd,但我仍然没有看到差异。 http://cherrypy.readthedocs.org/en/latest/deploy.html#tornado

这是我的入门代码。任何人都可以帮助我吗?

cfg = {
'global' : {
  'server.socket_host' : Utils.gflags.FLAGS.bind_addr,
  'server.socket_port' : Utils.gflags.FLAGS.bind_port,
  'server.thread_pool' : 10,
  'engine.timeout_monitor.frequency' : gflags.FLAGS.request_time_out_secs,
},
'/static' : {"tools.sessions.on": False, 'tools.auth.on': False},
'/favicon.ico' : {"tools.sessions.on": False, 'tools.auth.on': False},
}

# To turn off the cherrypy errors on screen.
cfg['global'].update({'log.screen': False})
cfg['/static'].update({'tools.staticdir.on': True})
cfg['/static'].update({'tools.staticdir.dir': Utils.gflags.FLAGS.static_dir})
cfg['/favicon.ico'].update({'tools.staticfile.on': True})
cfg['/favicon.ico'].update({'tools.staticfile.filename':
                          Utils.gflags.FLAGS.favicon_file})


# Disable the auto reload on code change.
cherrypy.engine.autoreload.unsubscribe()

# Start the cherrypy
#Root() is defined somewhere else. Don't worry about that
cherrypy.quickstart(Root(), config = cfg)

2 个答案:

答案 0 :(得分:3)

是的,您似乎在此博客文章中提到的有关会话锁定的相同问题:http://blog.schmichael.com/2007/09/20/session-locking-and-performance-in-cherrypy/

基本上,解决方案是明确地将会话锁定在代码中的其他位置,以阻止所有其他请求。

cherrypy.session.acquire_lock()
cherrypy.session.release_lock()

答案 1 :(得分:1)

我看到您正在禁用静态文件上的会话工具,因此我假设阻止是由阻塞会话引起的,请查看documentation related to session locking

这个例子可能是说明性的:

"""Show the difference between explicit and implicit locking
on the cherrypy sessions.

To see the effects make sure your client can handle cookies,
for example any conventional web browser or curl with
a cookie jar.

The exposed routes are:

   /e/
   /e/block/[minutes]
   /e/blocked_hi/
   /e/unblocked_hi
   /i/
   /i/block/[minutes]
   /i/blocked_hi/
   /i/unblocked_hi

The application mounted on /e/ has the sessions *explicitly* locked and
the applicaiton mounted on /i/ has the sessions *implicitly* locked.

You can make any concurrent request on the /e branch and you
will not have any blocking.

If you do the requests on the following steps:
  1. /i/
  2. /i/block
  3. /i/blocked_hi

The step 3 is going to be blocked because of the step 2, you can wait a minute
and when the request on step 2 ends it will inmediatly complete the step 3.
Also any request that you do to /i/unblocked_hi will respond immediately regardless
of any blocking.

In general if you call:

 1. /i/ or /e/ and then
 2. /i/block
 3. Any request to:
        /i/
        /i/blocked_hi
        /e/
    are going to be blocked in until /i/block finish.
"""
import time

import cherrypy as cp


class _App:

    @cp.expose
    def block(self, m=1):
        """Sleep for `m` minutes and return."""
        time.sleep(float(m) * 60)
        return "I have blocked this request {}".format(m)

    @cp.expose
    def blocked_hi(self):
        """It can be blocked if the blocked method is executing,
        the session have content and is locked.
        """
        return """Hi, I could have been blocked by a session.
        Session content: {}\n""".format(dict(cp.session))

    @cp.expose
    def unblocked_hi(self):
        return "Hi, I'm not blocked!"


class ImplicitlyLockedApp(_App):

    @cp.expose
    def index(self):
        cp.session['foo'] =  'bar'
        return "I've just set the session content to {}".format(dict(cp.session))


class ExplicitlyLockedApp(_App):

    @cp.expose
    def index(self):
        # This method can be blocked by /i/block because of the
        # acquire_lock/release_lock calls.
        cp.session.acquire_lock()
        cp.session['foo'] =  'bar'
        cp.session.release_lock()
        return "I've just set the session content to {}".format(dict(cp.session))


if __name__ == '__main__':
    cp.tree.mount(ImplicitlyLockedApp(), '/i', config={
        '/': {
            'tools.sessions.on': True
        },
        '/unblocked_hi': { # Disable the session tool to avoid any locking
            'tools.sessions.on': False
        }
    })
    cp.tree.mount(ExplicitlyLockedApp(), '/e', config={
        '/': {
            'tools.sessions.on': True,
            'tools.sessions.locking': 'explicit' # This is the magic bit.
        },
        '/unblocked_hi': { # Rather irrelevant on this case
            'tools.sessions.on': False
        }
    })
    cp.engine.start()
    cp.engine.block()