tornado 协程的一次分歧

大约是昨天,和同事在讨论tornado 异步的使用时,发生了一次讨论,与其说是讨论,不如说是,各持观点,想探究一下到底是怎么回事儿。

1 一个请求,涉及的后台代码是cpu密集型的,能不能用yield?有没有效果?

2 tornado异步装饰器gen.coroutine 中,返回数据是用raise gen.Return 还是可以直接用return?

在这之前,需要对tornado有个简单的了解:一个异步非阻塞的web框架,能够让那些原本读取文件,或者后端发起网络请求,数据库读取的等待时间省略掉,用来处理新的请求,增大网站的承载能力。

那么,开始讨论第一个问题。前面说到,tornado的异步非阻塞,是节省等待时间,用于处理请求。通常情况下,如果真的有一个耗时的,cpu密集型的处理,一般是交给celery来做,等待它做完了,在回来接着处理。基于这点,同事的观点是,如果cpu密集且耗时,是直接给celery做,如果不耗时,那么不需要中断当前处理跳出去处理新的请求,同时,他认为在tornado中,加上yield不会起到中断处理跳出去处理新请求的效果。而我的观点是,它是可以实现中断一个cpu密集的处理,处理新请求(实测),当然,方式,仅仅需要一个yield单独占一行而已。至于实际效果,我对此的看法是,前期可能没太大需要,但是当需求的迸发数增大,那么这是一个在现有的资源不变情况下,优化项目的一个方式?

为什么这么认为?tornado是以异步非阻塞带来的大迸发为特点的,而cpu一直在运行,并不会因为中断而减少处理时间,正如:在不优化算法的前提下,就算中断了处理,等会儿接着处理,也没有实际的改善处理时间,甚至会让当前的处理时间变长,而交给celery做,相当于后台有一个专用于此类任务的服务,能够直接的改善。但是,很多处理并不是一开始设定就会交给celery处理的,此类处理可能耗时并不长,大约1-2-3-4秒,程序设计之初并不会想着把此类请求更后台去处理。对于用户的体验,就会发生1-2-3-4秒的阻塞,这是一个不容易引起警觉的问题。而如果在编写的时候注意这一点,那么这1-2-3-4秒的处理,如果能够实现分次执行,在访问量不大时,对该次请求来说,并不会有太大延长,不会展现优势。但如果访问量大幅提升,每个请求都阻塞1-2-3-4秒,毫无疑问,这是可怕的。把请求中断,就能够很大程度的满足迸发?我是这么理解的

第二个问题,gen.coroutine中,能够使用return返回数据?

经过实验,结果显示:在python2中,生成器本身就不能用return返回,就算是gen.coroutine装饰也是一样,在python编译阶段就会报错,程序无法运行,需要用raise gen.Return 让生成器捕获结果。而在python3中,gen.coroutine 中是可以用return返回数据的,当然,原因可能是python3本身的生成器也支持return在里面,而gen.coroutine也能捕获到。但是,tornado的文档中,还是推荐用raise 让coroutine捕获结果。至于原因?在性能上,暂时没办法得知。而在项目中,我猜测,这可能是出于python版本兼容考虑。python的版本向上不兼容一直是个问题,也是在开发中需要注意的,而保持一个固定的返回方式,在尝试写一个既能在python2中运行,也能在python3中运行的项目时,是有好处的。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20171220G0VTFI00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券