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;
}
可是中间还是有机率切到同一个端口上面,然后又要等待处理,有什么其他处理方面吗?
1
keithsun80 2015-10-15 16:13:21 +08:00 1
epoll, 去搜 tornado 异步
|
2
adrianzhang 2015-10-15 16:16:31 +08:00 1
用 Tornado 本身就是因为要解决同步阻塞。您这是没用到其精髓。
|
3
ryanking8215 2015-10-15 16:17:29 +08:00 1
把耗时操作交给后台,不阻塞 ternado 的 loop 。 try celery
|
4
dai269619118 OP |
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 |
6
tigerstudent 2015-10-15 16:44:36 +08:00 via Android 1
Tornado 没有智能到任何代码异步执行,你得遵循它的规则
|
7
dai269619118 OP @mouer 谢谢 再请教你一个问题 tornado 异步能用到哪些地方?
|
8
mouer 2015-10-15 16:48:46 +08:00
@dai269619118 任何需要同步等的地方,比如访问 mysql ,调用 redis ,请求一个 url ,执行一段本地程序等等。
|
9
dai269619118 OP @mouer 非常感谢 明白了
|
10
phithon 2015-10-15 17:02:49 +08:00 1
耗时操作,比如 bcrypt 加密,我是交给 concurrent.futures.ThreadPoolExecutor 所创建的线程池去执行,然后 yield 等待执行结果切换到其他任务上。
具体可以看 Minos 的源码 https://github.com/phith0n/Minos |
12
tabris17 2015-10-15 17:05:14 +08:00 1
异步框架使用异步 IO 库,耗时的操作放在框架外进行,在代码中不应有阻塞操作
|
13
mouer 2015-10-15 17:20:48 +08:00 1
@wy315700 推荐看下 facebook 的实践,或者搜下赵海平的演讲,另外: http://www.bo56.com/download/facebook_mysql_async.pdf 可以看下,是可以异步的。
|
14
wy315700 2015-10-15 17:30:06 +08:00
@mouer 是可以用的,但是不推荐,,尤其是 MySQL ,本身不是为异步准备的,如果连接缓慢,应该去优化查询。
仅限于内网数据库的情况,如果数据库连接很慢,比如在公网,那就另外。。。 |
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 个数一样好了,完全并发不起来的。 |
16
wy315700 2015-10-15 18:09:06 +08:00
@mouer
我测出来效果不好,如果连接池过大,并发量高的话数据库会瞬间收到很大的压力,如果连接池少了,我用的 sqlalchemy ,不知道是不是他的连接池管理有问题,如果连接池满了,就挂了。。。 |
17
china521 2015-10-15 18:15:38 +08:00 via iPhone
你需要 golang 别跟 tornado 过不去 太小众了
|
18
mouer 2015-10-15 18:19:41 +08:00 1
@wy315700 我在生产环境里面用过 pymysql + tornado_mysql , 地址: https://github.com/PyMySQL/Tornado-MySQL , 自己封装下 pool 用的很完美,有机会可以试试
|
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() ``` |
20
neoblackcap 2015-10-15 23:51:51 +08:00 1
@wy315700 本地磁盘 IO 封装成网络 IO 就好了(另起一个 service 专门处理 IO ),
|
21
sujin190 2015-10-19 00:30:05 +08:00
@wy315700 正常使用 mysql 上百万数据,有索引也得十几到几十毫秒才能返回,不用异步的话,这期间 tornado 就什么也不能做了
|
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 相当于是一个长时间的堵塞请求,正确用法是启动另一个线程或者进程进行处理。 |