关于 tornado 阻塞的问题

2015-10-15 16:11:43 +08:00
 dai269619118
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;
    }

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

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

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

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

ps:如果要 sleep ,也应该用 gen.sleep(100),忘记了,大概是这么写, T_T
tigerstudent
2015-10-15 16:44:36 +08:00
Tornado 没有智能到任何代码异步执行,你得遵循它的规则
dai269619118
2015-10-15 16:44:54 +08:00
@mouer 谢谢 再请教你一个问题 tornado 异步能用到哪些地方?
mouer
2015-10-15 16:48:46 +08:00
@dai269619118 任何需要同步等的地方,比如访问 mysql ,调用 redis ,请求一个 url ,执行一段本地程序等等。
dai269619118
2015-10-15 16:56:55 +08:00
@mouer 非常感谢 明白了
phithon
2015-10-15 17:02:49 +08:00
耗时操作,比如 bcrypt 加密,我是交给 concurrent.futures.ThreadPoolExecutor 所创建的线程池去执行,然后 yield 等待执行结果切换到其他任务上。
具体可以看 Minos 的源码 https://github.com/phith0n/Minos
wy315700
2015-10-15 17:04:47 +08:00
@mouer 访问 MySQL 和 redis 其实不推荐异步访问,,,
tabris17
2015-10-15 17:05:14 +08:00
异步框架使用异步 IO 库,耗时的操作放在框架外进行,在代码中不应有阻塞操作
mouer
2015-10-15 17:20:48 +08:00
@wy315700 推荐看下 facebook 的实践,或者搜下赵海平的演讲,另外: http://www.bo56.com/download/facebook_mysql_async.pdf 可以看下,是可以异步的。
wy315700
2015-10-15 17:30:06 +08:00
@mouer 是可以用的,但是不推荐,,尤其是 MySQL ,本身不是为异步准备的,如果连接缓慢,应该去优化查询。
仅限于内网数据库的情况,如果数据库连接很慢,比如在公网,那就另外。。。
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
2015-10-15 18:09:06 +08:00
@mouer
我测出来效果不好,如果连接池过大,并发量高的话数据库会瞬间收到很大的压力,如果连接池少了,我用的 sqlalchemy ,不知道是不是他的连接池管理有问题,如果连接池满了,就挂了。。。
china521
2015-10-15 18:15:38 +08:00
你需要 golang 别跟 tornado 过不去 太小众了
mouer
2015-10-15 18:19:41 +08:00
@wy315700 我在生产环境里面用过 pymysql + tornado_mysql , 地址: https://github.com/PyMySQL/Tornado-MySQL , 自己封装下 pool 用的很完美,有机会可以试试
zeayes
2015-10-15 18:22:24 +08:00
tornado 的异步是针对网络 IO 的异步, time.sleep 会阻塞整个进程,所以是需要等待的。
下面这样就不会阻塞了。
```python
@gen.coroutine
def get(self):
yield gen.Task(ioloop.IOLoop.instance().add_timeout, time.time() + 100)
self.write()
```
neoblackcap
2015-10-15 23:51:51 +08:00
@wy315700 本地磁盘 IO 封装成网络 IO 就好了(另起一个 service 专门处理 IO ),

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/228298

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX