Python cherrypy是如何工作的?与tornado相比,当并发度较低时,它能很好地处理请求

Python cherrypy是如何工作的?与tornado相比,当并发度较低时,它能很好地处理请求,python,asynchronous,webserver,tornado,cherrypy,Python,Asynchronous,Webserver,Tornado,Cherrypy,我在cherrypy(使用web.py作为框架)和tornado上进行了一项测试,从互联网上检索网页 我有三个测试用例使用sakege向服务器发送请求(-c表示用户数;-t表示测试时间)。代码低于测试结果 1.web.py(cherrpy) 2.龙卷风同步 3.龙卷风异步 性能分析: tornado同步

我在cherrypy(使用web.py作为框架)和tornado上进行了一项测试,从互联网上检索网页

我有三个测试用例使用
sakege
向服务器发送请求(-c表示用户数;-t表示测试时间)。代码低于测试结果

1.web.py(cherrpy) 2.龙卷风同步 3.龙卷风异步 性能分析: tornado同步 问题1: 我知道,使用异步体系结构可以显著提高web服务器的性能

我很好奇tornado异步体系结构和web.py(cherry)之间的区别

我认为tornado同步模式可以一个接一个地处理请求,但是cherrypy是如何使用多线程工作的呢?但是我没有看到记忆有很大的增长。Cherrypy可能同时处理多个请求。它如何解决程序阻塞问题

问题2: 我是否可以在不使用异步技术的情况下提高tornado同步模式的性能?我认为龙卷风可以做得更好

Web.py代码: 龙卷风同步: 龙卷风异步:
要回答问题1

龙卷风是单线程的。如果像在同步示例中那样阻塞主线程,那么在阻塞调用返回之前,单个线程无法执行任何操作。这将同步示例一次限制为一个请求

我对web.py不是特别熟悉,但查看它似乎使用了线程混合,这表明它不限于一次处理一个请求。当第一个请求传入时,它由一个线程处理。该线程将阻塞,直到HTTP客户端调用返回,但其他线程可以自由处理进一步的传入请求。这允许一次处理更多的请求


我怀疑,如果您使用Tornado模拟这种情况,例如,通过将HTTP客户端请求传递到线程池,那么您将看到类似的吞吐量。

测试代码中的大部分处理程序时间都花在
client.fetch(…)
-有效地等待连接和套接字上的传入数据-同时不阻止其他潜在的Python线程

因此,您的“性能度量”主要取决于所讨论框架的最大有效处理线程数和“百度”服务器允许从您的IP进行的最大并行连接数

wep.py的
CherryPyWSGIServer
web.wsgiserver.CherryPyWSGIServer
副本被默认的
web.httpserver.runsimple()
确实默认使用线程-10。
线程不会在这里大量增加内存使用。这里,库和Python解释器本身占用了大部分内存。 CherryPyWSGIServer的(10)个处理工作线程都是从一开始就启动的。 可选的web.httpserver.runbasic()也使用线程——通过Python的内置httpserver和
SocketServer.ThreadingMixIn
。这个线程为每个请求启动一个新线程。可能是“无限”的线程数-但每个请求的线程启动都有开销

tornado
异步模式也可能使用更多/无限数量的线程(?),这可能解释了与web.py的区别

您的测试没有说明服务器和处理程序框架本身的执行速度。您可以简单地增加web.py的CherryPyWSGIServer中的最大线程数。并行执行您的
客户机.fetch(…)
,在某种程度上需要获得更高的“性能”

要测试服务器/框架的速度(开销成本),只需返回一个字符串、一个数据库查询或从本地内容呈现的典型完整网页


在一个进程中,基于多线程CPython的web&app服务器最终不能使用多个CPU核心(目前服务器硬件上通常使用8个CPU核心),因为CPython中的GIL仅用于某些I/O。因此,如果CPU负载成为一个因素(而不是网络或数据库速度),可以考虑Jython或多进程方法

我非常怀疑您的性能可能会受到
fetch>的限制http://www.baidu.com/)
比您使用的web框架多得多。当你提供静态内容,或者至少是相同的本地生成内容时,试着比较一下。这没关系。我正在比较不同web服务器的性能。“fetch(')”只是一个阻塞代码。cherrypy是从哪里来的?web.py使用cherrypy作为内置的HttpServers当我测试web.py时,我一直在观察cherrpy占用的内存变化。我知道,通常情况下,linux中的线程占用了8m。同时,在开始时,cherrypy占用了1200万,当它处理请求时,只占用了1500万。我不认为它使用多线程。这就是为什么我对cherrypy感到好奇。
  siege ip -c20 -t100s             server can handle 2747requests  
  siege ip -c200 -t30s             server can handle 1361requests
  siege ip -c500 -t30s             server can handle 170requests
  siege ip -c20 -t100s             server can handle 600requests  
  siege ip -c200 -t30s             server can handle 200requests
  siege ip -c500 -t30s             server can handle 116requests
  siege ip -c20 -t100s             server can handle 3022requests  
  siege ip -c200 -t30s             server can handle 2259requests
  siege ip -c500 -t30s             server can handle 471requests
import web
import tornado.httpclient
urls = (
    '/(.*)', 'hello'
)
app = web.application(urls, globals())

class hello:
    def GET(self, name):
        client = tornado.httpclient.HTTPClient()
        response=client.fetch("http://www.baidu.com/")
        return response.body

if __name__ == "__main__":
    app.run()
import tornado.ioloop
import tornado.options
import tornado.web
import tornado.httpclient
from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)
class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        client = tornado.httpclient.HTTPClient()
        response = client.fetch("http://www.baidu.com/" )
        self.write(response.body)


if __name__=='__main__':
    tornado.options.parse_command_line()
    app=tornado.web.Application(handlers=[(r'/',IndexHandler)])
    http_server=tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import tornado.httpclient
from tornado.options import define, options
define("port", default=8001, help="run on the given port", type=int)
class IndexHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self):
        client = tornado.httpclient.AsyncHTTPClient()
        response = client.fetch("http://www.baidu.com/" ,callback=self.on_response)

    def on_response(self,response):
        self.write(response.body)
        self.finish()

if __name__=='__main__':
    tornado.options.parse_command_line()
    app=tornado.web.Application(handlers=[(r'/',IndexHandler)])
    http_server=tornado.httpserver.HTTPServer(app)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()