关于 tornado 阻塞的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dai269619118
V2EX    Tornado

关于 tornado 阻塞的问题

  •  
  •   dai269619118 2015-10-15 16:11:43 +08:00 8161 次点击
    这是一个创建于 3699 天前的主题,其中的信息可能已经有所发展或是发生改变。
    def get(self): time.sleep(100) self.write('hello test') 

    如果程序执行的时候中间处理一个需要很多时间,这个时候有一个新的请求
    那么第二个请求需要等待第一个请求执行完才开始执行第二个操作
    接着用 nginx 做了一个负载均衡,开了 3 个 tornado

    upstream to.com{ server 127.0.0.1:8887; server 127.0.0.1:8888; server 127.0.0.1:8889; } 

    可是中间还是有机率切到同一个端口上面,然后又要等待处理,有什么其他处理方面吗?

    22 条回复    2015-11-20 09:55:01 +08:00
    keithsun80
        1
    keithsun80  
       2015-10-15 16:13:21 +08:00   1
    epoll, 去搜 tornado 异步
    adrianzhang
        2
    adrianzhang  
       2015-10-15 16:16:31 +08:00   1
    用 Tornado 本身就是因为要解决同步阻塞。您这是没用到其精髓。
    ryanking8215
        3
    ryanking8215  
       2015-10-15 16:17:29 +08:00   1
    把耗时操作交给后台,不阻塞 ternado 的 loop 。 try celery
    dai269619118
        4
    dai269619118  
    OP
       2015-10-15 16:29:09 +08:00
    @keithsun80
    @adrianzhang
    @ryanking8215
    谢谢 我再仔细看看 tornado 异步
    mouer
        5
    mouer  
       2015-10-15 16:35:59 +08:00   1
    这块你理解的不对, time.sleep(100),有什么操作可以 cpu 运算 100 秒?

    一般情况,我们用 tornado 都是把同步操作给异步化,比如访问 mysql ,可以看下 tornado 的 gen.coroutine 。

    当程序在运行到同步操作的时候, ioloop 会切换到其他的 coroutine 去执行的。

    ps:如果要 sleep ,也应该用 gen.sleep(100),忘记了,大概是这么写, T_T
    tigerstudent
        6
    tigerstudent  
       2015-10-15 16:44:36 +08:00 via Android   1
    Tornado 没有智能到任何代码异步执行,你得遵循它的规则
    dai269619118
        7
    dai269619118  
    OP
       2015-10-15 16:44:54 +08:00
    @mouer 谢谢 再请教你一个问题 tornado 异步能用到哪些地方?
    mouer
        8
    mouer  
       2015-10-15 16:48:46 +08:00
    @dai269619118 任何需要同步等的地方,比如访问 mysql ,调用 redis ,请求一个 url ,执行一段本地程序等等。
    dai269619118
        9
    dai269619118  
    OP
       2015-10-15 16:56:55 +08:00
    @mouer 非常感谢 明白了
    phithon
        10
    phithon  
       2015-10-15 17:02:49 +08:00   1
    耗时操作,比如 bcrypt 加密,我是交给 concurrent.futures.ThreadPoolExecutor 所创建的线程池去执行,然后 yield 等待执行结果切换到其他任务上。
    具体可以看 Minos 的源码 https://github.com/phith0n/Minos
    wy315700
        11
    wy315700  
       2015-10-15 17:04:47 +08:00   1
    @mouer 访问 MySQL 和 redis 其实不推荐异步访问,,,
    tabris17
        12
    tabris17  
       2015-10-15 17:05:14 +08:00   1
    异步框架使用异步 IO 库,耗时的操作放在框架外进行,在代码中不应有阻塞操作
    mouer
        13
    mouer  
       2015-10-15 17:20:48 +08:00   1
    @wy315700 推荐看下 facebook 的实践,或者搜下赵海平的演讲,另外: http://www.bo56.com/download/facebook_mysql_async.pdf 可以看下,是可以异步的。
    wy315700
        14
    wy315700  
       2015-10-15 17:30:06 +08:00
    @mouer 是可以用的,但是不推荐,,尤其是 MySQL ,本身不是为异步准备的,如果连接缓慢,应该去优化查询。
    仅限于内网数据库的情况,如果数据库连接很慢,比如在公网,那就另外。。。
    mouer
        15
    mouer  
       2015-10-15 17:44:35 +08:00
    @wy315700 我觉得我们说的“异步”不是一回事,我所说的,是用 tornado 不用傻呵呵的等数据库返回结果,而且是可以用 yield 返回到 ioLoop ,然后取运行别的“协程”,一般来说,都是一个“协程”一个数据库连接的,“协程”结束, db 连接放回到池里面,可以参照 golang 的 mysql db 库看看。

    因为 python 有 GIL 的存在,用 tornado 非多线程的方式,难道让 cpu 去干等十几到几百毫秒而不去做别的事情?

    拿 java 来举例子,一般 tomcat 的线程数设置到 250 ,然后 db 的连接池是 20-30 不等,要是不推荐,或者这么做起来有问题,那数据库的连接池直接和 cpu 个数一样好了,完全并发不起来的。
    wy315700
        16
    wy315700  
       2015-10-15 18:09:06 +08:00
    @mouer
    我测出来效果不好,如果连接池过大,并发量高的话数据库会瞬间收到很大的压力,如果连接池少了,我用的 sqlalchemy ,不知道是不是他的连接池管理有问题,如果连接池满了,就挂了。。。
    china521
        17
    china521  
       2015-10-15 18:15:38 +08:00 via iPhone
    你需要 golang 别跟 tornado 过不去 太小众了
    mouer
        18
    mouer  
       2015-10-15 18:19:41 +08:00   1
    @wy315700 我在生产环境里面用过 pymysql + tornado_mysql , 地址: https://github.com/PyMySQL/Tornado-MySQL , 自己封装下 pool 用的很完美,有机会可以试试
    zeayes
        19
    zeayes  
       2015-10-15 18:22:24 +08:00   1
    tornado 的异步是针对网络 IO 的异步, time.sleep 会阻塞整个进程,所以是需要等待的。
    下面这样就不会阻塞了。
    ```python
    @gen.coroutine
    def get(self):
    yield gen.Task(ioloop.IOLoop.instance().add_timeout, time.time() + 100)
    self.write()
    ```
    neoblackcap
        20
    neoblackcap  
       2015-10-15 23:51:51 +08:00   1
    @wy315700 本地磁盘 IO 封装成网络 IO 就好了(另起一个 service 专门处理 IO ),
    sujin190
        21
    sujin190  
       2015-10-19 00:30:05 +08:00
    @wy315700 正常使用 mysql 上百万数据,有索引也得十几到几十毫秒才能返回,不用异步的话,这期间 tornado 就什么也不能做了
    say2old
        22
    say2old  
       2015-11-20 09:55:01 +08:00   1
    Tornado 官网上说的很清楚:

    To minimize the cost of concurrent connections, Tornado uses a single-threaded event loop. This means that all application code should aim to be asynchronous and non-blocking because only one operation can be active at a time.

    这个框架本质是在一个线程里做 event loop ( while True: blahblah 那种),所有的请求一个接一个处理。确保你的每一个请求都是轻量级的操作或者异步操作,不堵塞后面的请求。你的 sleep 相当于是一个长时间的堵塞请求,正确用法是启动另一个线程或者进程进行处理。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3100 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 00:42 PVG 08:42 LAX 16:42 JFK 19:42
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86