问题
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