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/
dai269619118
V2EX  ›  Tornado

关于 tornado 阻塞的问题

  •  
  •   dai269619118 · 2015-10-15 16:11:43 +08:00 · 7658 次点击
    这是一个创建于 3325 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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   ·   实用小工具   ·   4345 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 01:04 · PVG 09:04 · LAX 17:04 · JFK 20:04
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.