V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Tornado Documentation
http://www.v2ex.com/tornado/
Tornado on GitHub
https://github.com/facebook/tornado/
Tornado Gists
http://tornadogists.org/
geew
V2EX  ›  Tornado

有关Tornado 异步的讨论

  •  
  •   geew · 2013-11-11 10:21:06 +08:00 · 20299 次点击
    这是一个创建于 3812 天前的主题,其中的信息可能已经有所发展或是发生改变。
    最近开始用tornado, 之前接触过的框架有django和flask. tornado的标榜就是异步, 但是在开发的过程中没怎么感觉到. 可能是我的使用问题吧.对异步这些东西的理解不是那么的透彻. 故此希望大家一起讨论下:

    1.tornado异步的存在是需要程序中的各个处理均是异步的才行么? 比如访问数据库, 同步的访问的话tornado的异步貌似没有作用. 以及一些比较耗时间的任务, 都需要异步的写法才行, 并不是yield tornado.gen.Task(model.func, args=args)这样了之后就是异步执行了.

    2.如果一成立的话每个函数都需要异步的写法, 问题就来了, 异步的程序怎么写呢? 我觉得这个问题挺大, 对异步的东西不是很了解. 还是比如访问数据库, 怎么做到异步的呢? 需要响应的数据库驱动支持么还是?

    3.如果这样的话, tornado的优势在哪里呢? tornado的堵塞是会堵塞整个服务器, 好恐怖的赶脚.

    PS: 好吧, 我就是想问问异步的程序怎么写的?
    比如: yield tornado.gen.Task(model.func, args=args)
    然后:
    def func(args, callback=None):
    time.sleep(10)
    data = get_from_mysql(args)
    if callback: callback(data)
    return data
    其实同样的堵塞, 完全没有异步执行, 那以上的程序怎么改成异步的呢??
    35 条回复    2014-11-26 11:48:25 +08:00
    llbgurs
        1
    llbgurs  
       2013-11-11 10:34:46 +08:00
    只有io异步吧,数据库的library需要支持异步操作
    shiny
        2
    shiny  
       2013-11-11 10:52:22 +08:00
    支持异步的库在这里可以找到: https://github.com/facebook/tornado/wiki/Links
    tornado 真用起来还是挺麻烦的。
    Veelian
        3
    Veelian  
       2013-11-11 10:52:50 +08:00 via iPhone
    time.sleep(10)会block你的应用的
    Shevckcccc
        4
    Shevckcccc  
       2013-11-11 10:54:53 +08:00
    楼主我遇到了跟你一样的问题,然后这是v2ex上的异步讨论 http://v2ex.com/t/85762#reply21
    binux
        5
    binux  
       2013-11-11 10:55:23 +08:00
    yield tornado.gen.Task 只是语法糖,需要函数修饰
    如果你才入门,想知道异步是怎么执行的话,不要看这种写法,去看callback的写法

    callback的地方就是异步的,没有就是同步的
    geew
        6
    geew  
    OP
       2013-11-11 10:58:37 +08:00
    @binux 真心想看 有推荐的一些例子么
    binux
        7
    binux  
       2013-11-11 11:01:30 +08:00   ❤️ 1
    @geew http://www.tornadoweb.org/en/stable/httpclient.html#tornado.httpclient.AsyncHTTPClient

    除此之外就是io库是异步的了,用得上的只有这个了
    cctvsmg
        8
    cctvsmg  
       2013-11-11 11:51:56 +08:00   ❤️ 1
    我试验过几个tornado的异步驱动
    比如umysqldb psycopg2 motor
    比较神奇的用ab试验benchmark
    结果表明这些异步驱动的性能很差

    其中最神奇的是motor这货居然会卡死
    motor用了greenlet,不知道是不是greenlet和tornado有不兼容的地方

    最后采取的方案是.....
    从GAE里面扣出来了一个叫ndb的orm
    再把后端的数据库接口换成自己的mongodb服务器(也可以换成mysql)
    运行的时候用的runtime环境是最新版的pypy2.2(性能爆表)

    这个框架的性能大概情况:
    如果tornado helloword 每次请求查询一次数据库
    ab设置并发为100-300,单核情况下tornado的rps可以到3000左右
    4核服务器跑个上万没问题

    因为涉及的东西都是纯python的可以在bae sae gae heroku 等等平台上随便迁移
    evan00
        9
    evan00  
       2013-11-11 12:35:26 +08:00
    @cctvsmg 可不分享下 你说的GAE里扣出的那块?
    cctvsmg
        10
    cctvsmg  
       2013-11-11 12:51:02 +08:00   ❤️ 1
    @evan00 才弄好,只跑了几个benchmark试验了下demo,等跑一段时间看看稳定性修改下bug,会公开的
    alsotang
        11
    alsotang  
       2013-11-11 13:20:48 +08:00
    在这个 JS 准备一统天下的年代,玩异步服务器还是来玩 Node 吧。
    fansgentle
        12
    fansgentle  
       2013-11-11 14:02:40 +08:00   ❤️ 2
    Tornado的异步客户端直接写起来并不简单,可以参考官方的异步客户端tornado.httpclient.AsyncHTTPClient[https://github.com/facebook/tornado/blob/master/tornado/httpclient.py],要想使自己的服务是异步的,仅仅用上装饰器、yield是不够的,必须保证自己的写的客户端是异步的,即要用到tornado.ioloop.IOLoop,如 想让数据库操作支持异步,就可以自己仿照AsyncHTTPClient、在IOLoop的基础上实现一个数据库客户端。

    要想写异步Tornado最简单的方法是用Celery: Distributed Task Queue[http://www.celeryproject.org],Tornado接到请求后把所有的业务逻辑处理、数据库操作及其他相关的IO操作等交给Celery来处理,不管耗时多长,处理完后异步返回,就能保证整个服务是完全异步的,当然,简单的不涉及太多IO或太复杂计算的操作还是建议用Tornado同步处理,因为把任务交给Celery的RabbitMQ通信会有一定网络IO开销。

    Tornado的Celery适配器:https://github.com/mher/tornado-celery/
    Celery的其他相关适配器:http://docs.celeryproject.org/en/latest/getting-started/introduction.html#framework-integration
    异步的代码可以这样:
    @tornado.web.asynchronous
    @tornado.gen.coroutine
    def get(self, *args, **kwargs):
    response = yield tornado.gen.Task(celery_task_do_something.apply_async, args=[self.request.arguments])
    self.finish(response.result)

    Celery很赞,可以自己实践下,回用上瘾的 ^_^ ~~
    fansgentle
        13
    fansgentle  
       2013-11-11 14:06:24 +08:00
    @fansgentle 基本上都是手敲的格式还是这么乱,还有错别字 ...
    geew
        14
    geew  
    OP
       2013-11-11 14:15:12 +08:00
    @cctvsmg 公开之时勿忘我哈
    geew
        15
    geew  
    OP
       2013-11-11 14:18:14 +08:00
    @cctvsmg 感觉现在项目性能方面的问题比较大.
    ab测试 -c300 -n1000
    Requests per second: 64.20 [#/sec] (mean)

    中间还加了nginx. 测试机的测试结果
    geew
        16
    geew  
    OP
       2013-11-11 14:20:34 +08:00
    @fansgentle 很赞的回答 谢谢
    geew
        17
    geew  
    OP
       2013-11-11 15:41:38 +08:00
    @cctvsmg 单核情况下rps有30000?
    是Requests per second: 684.21 [#/sec] (mean)
    这个值吗?
    我随便用tornado+sqlalchemy, 单次请求访问一次数据库. ab 300的并发, 最多只能达到这个值.
    usoluyun
        18
    usoluyun  
       2013-11-12 01:21:40 +08:00
    @geew 瓶颈db那儿吧。什么事情不干,光是开关connection,小得vps能到300就不错了
    zenliver
        19
    zenliver  
       2013-11-12 16:24:26 +08:00
    fansgentle
        20
    fansgentle  
       2013-11-12 18:49:08 +08:00
    @zenliver 代码不到20行啊,赞,有空试下效果
    zenliver
        21
    zenliver  
       2013-11-12 22:00:36 +08:00
    @fansgentle 程序随小, 五脏俱全,,,呵呵
    geew
        23
    geew  
    OP
       2013-11-22 14:46:47 +08:00
    @cctvsmg 少年 说好的ORM呢 想研究研究下 谢谢了
    cctvsmg
        24
    cctvsmg  
       2013-11-22 15:08:05 +08:00   ❤️ 1
    @geew 可以先研究研究peewee 和 umysqldb相结合,另外https://github.com/BeanYoung/peewee这个版本加进去了connection pool,ndb那个因为是菲关系型的orm还在试验中。
    geew
        25
    geew  
    OP
       2013-11-22 17:49:23 +08:00
    @justfly 使用celery的话只要 pip install tornado-celery就行了吗?
    import tcelery 来用的话会有这个错误:
    怎么 AttributeError: 'module' object has no attribute 'celery_task'

    tcelery里面没有celery_task这个东西呢??
    justfly
        26
    justfly  
       2013-11-22 20:55:48 +08:00   ❤️ 1
    @geew 新版本问题吧,是我引用的代码,celery依赖环境很多,我没有测试。你可以看一下这里的介绍:https://github.com/mher/tornado-celery

    不出意外你要启动一个单独的 celery 进程来专门处理这些异步job的。像这样:http://docs.celeryproject.org/en/latest/getting-started/first-steps-with-celery.html

    请求不是非常频繁的话用线程吧,依赖少一些,线程池大小要自己把握,毕竟不配置的话默认linux一个线程8M 内存
    geew
        27
    geew  
    OP
       2013-11-25 11:33:10 +08:00
    @zenliver 试过了 但要tornado3.x以上才能运行的
    geew
        28
    geew  
    OP
       2013-11-25 11:34:57 +08:00
    @justfly 嗯 还得研究研究下. 你引用的代码是使用了这个的https://github.com/mayflaver/tornado-celery . tornado 2.x不能运行. 3x才行

    有用tornado-celery tornado版本2.2的demo么, 照着官方的做总是出现各种各样的问题
    geew
        29
    geew  
    OP
       2013-11-25 12:01:19 +08:00
    @justfly
    @fansgentle
    有些浮躁了 我还是好好看看下celery的文档再说
    neoz
        30
    neoz  
       2014-06-21 13:31:27 +08:00
    @fansgentle 请问tornado的request_time应该怎么实现?
    fansgentle
        31
    fansgentle  
       2014-06-25 10:05:16 +08:00
    自己写的话可以这样

    class BaseHandler(tornado.web.RequestHandler):

    def initialize(self):
    self._start_time = time.time()

    def on_finish(self):
    self._finish_time = time.time()
    # deal request_time

    另tornado.web.RequestHandler实例的request属性有request_time方法:
    https://github.com/tornadoweb/tornado/blob/4e9de2e43f50ae8a5317d4287d592904cf39a9e5/tornado/httputil.py#L399
    fansgentle
        32
    fansgentle  
       2014-06-25 10:07:28 +08:00
    @neoz 以上
    sujunj2005
        33
    sujunj2005  
       2014-11-26 11:27:36 +08:00
    这么一说tornado易用性没有这么好啊,亏我们还在用tornado+motor
    geew
        34
    geew  
    OP
       2014-11-26 11:47:52 +08:00
    @sujunj2005 好不好各有评判吧 不过要是真正的用好tornado 也是挺不容易的
    geew
        35
    geew  
    OP
       2014-11-26 11:48:25 +08:00
    @sujunj2005 http://www.nowamagic.net/academy/detail/13321030 看源码去吧 估计会有其他的体会
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   940 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 20:03 · PVG 04:03 · LAX 13:03 · JFK 16:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.