How to make CherryPy serve concurrent requests?

試著忘記壹切 提交于 2019-12-24 13:51:34

问题


I have read that cherrypy uses a threadpool of its own. But I am unable to see the advantage of that.

Let's say I fire off a request which will take a long time and after that in another tab I fire off a request which will take a short time. If it really uses multithreading, the short request should complete before the long one. But I am seeing that first the long request gets completed and then the short time, as if everything is processed sequentially.

I have tried integrating with different uWSGI frameworks like Tornado and twistd, but still I don't see a difference. http://cherrypy.readthedocs.org/en/latest/deploy.html#tornado

This is my starter code. Can anyone help me out here?

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)

回答1:


Yes it looks like you're having the same issue mentioned in this blog post about session locking: http://blog.schmichael.com/2007/09/20/session-locking-and-performance-in-cherrypy/

Basically the solution is to explicitly lock your sessions at a different point in the code where it won't block all other requests.

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



回答2:


I see that you are disabling the session tool on the static files, so I assume that the blocking is caused by blocking sessions, check out the documentation related to session locking.

This example may be illustrative:

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


来源:https://stackoverflow.com/questions/28190526/how-to-make-cherrypy-serve-concurrent-requests

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!