Python 如何让CherryPy服务于并发请求?

Python 如何让CherryPy服务于并发请求?,python,multithreading,cherrypy,web-frameworks,Python,Multithreading,Cherrypy,Web Frameworks,我读到cherrypy使用自己的线程池。但我看不出这有什么好处 假设我发出一个需要很长时间的请求,然后在另一个选项卡中发出一个需要很短时间的请求。如果它真的使用多线程,那么短请求应该在长请求之前完成。但我看到,首先是长请求完成,然后是短时间,好像所有事情都是按顺序处理的 我已经尝试过与不同的uWSGI框架集成,比如Tornado和twistd,但仍然没有看到任何区别。 这是我的起始代码。有人能帮我吗 cfg = { 'global' : { 'server.socket_host' : U

我读到cherrypy使用自己的线程池。但我看不出这有什么好处

假设我发出一个需要很长时间的请求,然后在另一个选项卡中发出一个需要很短时间的请求。如果它真的使用多线程,那么短请求应该在长请求之前完成。但我看到,首先是长请求完成,然后是短时间,好像所有事情都是按顺序处理的

我已经尝试过与不同的uWSGI框架集成,比如Tornado和twistd,但仍然没有看到任何区别。

这是我的起始代码。有人能帮我吗

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)

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

该示例可以是说明性的:

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

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

该示例可以是说明性的:

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

是的,这篇关于会话锁定的博文中也提到了同样的问题:

基本上,解决方案是显式地将会话锁定在代码中的不同点上,这样就不会阻止所有其他请求

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

是的,这篇关于会话锁定的博文中也提到了同样的问题:

基本上,解决方案是显式地将会话锁定在代码中的不同点上,这样就不会阻止所有其他请求

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

您好,您确定浏览器在第二个选项卡上使用了不同的连接吗?它可能只是重复使用第一个请求,这意味着它将按顺序执行两个请求。但我确实需要在请求级别上的并发性,而不是在连接级别上的并发性。禁用会话可能是一种方式,我会检查。相关吗?您好,您确定浏览器在第二个选项卡上使用了不同的连接吗?它可能只是重复使用第一个请求,这意味着它将按顺序执行两个请求。但我确实需要在请求级别上的并发性,而不是在连接级别上的并发性。禁用会话可能是一种方式,我会检查。相关吗?谢谢,将禁用会话并查看其运行情况。谢谢,将禁用会话并查看其运行情况。谢谢。这就是问题所在。哇,错过一件多么微妙的事情,它产生了多么大的影响!谢谢这就是问题所在。哇,错过一件多么微妙的事情,它产生了多么大的影响!