tornado6与python3.7,异步新姿势
废话不多说,直接上代码
__auth__ = "aleimu"
__doc__ = "学习tornado6.0+ 版本与python3.7+"
import time
import asyncio
import tornado.gen
import tornado.web
import tornado.ioloop
import tornado.httpserver  # tornado的HTTP服务器实现
from tornado.options import define, options
from tornado.httpclient import HTTPClient, AsyncHTTPClient
from requests import get
settings = {'debug': True}
url = "http://127.0.0.1:5000/"  # 这是另个服务,请求5s后返回结果
# RuntimeError: Cannot run the event loop while another loop is running
# 解释:HTTPClient内部写 loop.run_xxx,因为那是启动event loop的命令,通常只再最最最外面用一次,之后的代码都应假设 loop 已经在运转了。
def synchronous_fetch(url):
    print("synchronous_fetch")
    try:
        http_client = HTTPClient()
        time.sleep(5)
        response = http_client.fetch(url)
        print(response.body)
    except Exception as e:
        print("Error: " + str(e))
        return str(e)
    http_client.close()
    return response.body
# 替代synchronous_fetch的同步请求,没有内置loop.run_xxx
def synchronous_get(url):
    response = get(url)
    time.sleep(5)
    print("synchronous_fetch")
    return response.text
# 简单的模拟异步操作,这里之后应该替换成各种异步库的函数
async def sleep():
    print("start sleep")
    await asyncio.sleep(5)
    print("end sleep")
# 异步请求
async def asynchronous_fetch(url):
    http_client = AsyncHTTPClient()
    response = await http_client.fetch(url)
    print("asynchronous_fetch")
    return response.body
# 测试
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world:%s" % self.request.request_time())
        self.finish()
        print("not finish!")
        return
# 同步阻塞
class synchronous_fetcher(tornado.web.RequestHandler):
    def get(self):
        self.write("%s,%s" % (synchronous_fetch(url), self.request.request_time()))
# 同步阻塞
class synchronous_geter(tornado.web.RequestHandler):
    def get(self):
        self.write("%s,%s" % (synchronous_get(url), self.request.request_time()))
# 异步阻塞,我以为curl "127.0.0.1:8888/1" 总耗时希望为5s,可是是25s,看来异步没搞好,以下的函数都是基于此改进的
class asynchronous_fetcher_1(tornado.web.RequestHandler):
    async def get(self):
        body = await asynchronous_fetch(url)
        for i in range(3):
            print("skip %s" % i)
            await tornado.gen.sleep(5)
        time.sleep(5)
        print("end request")
        self.write("%s,%s" % (body, self.request.request_time()))
# curl "127.0.0.1:8888/1"
# b'{\n  "data": "123"\n}\n',25.026000022888184
# 异步阻塞,效果同上,这里只是证明 tornado.gen.sleep(5)和asyncio.sleep(5) 效果一致
class asynchronous_fetcher_2(tornado.web.RequestHandler):
    async def get(self):
        body = await asynchronous_fetch(url)  # 关注协程完成后返回的结果
        for i in range(3):
            print("skip %s" % i)
            await sleep()
        time.sleep(5)
        print("end request")
        self.write("%s,%s" % (body, self.request.request_time()))
# curl "127.0.0.1:8888/2"
# b'{\n  "data": "123"\n}\n',25.039999961853027
# 异步非阻塞-将部分异步操作放入组中,实现loop管理
class asynchronous_fetcher_3(tornado.web.RequestHandler):
    async def get(self):
        body = await asynchronous_fetch(url)
        await asyncio.wait([sleep() for i in range(3)])
        print("end request")
        self.write("%s,%s" % (body, self.request.request_time()))
# curl "127.0.0.1:8888/3"
# b'{\n  "data": "123"\n}\n',10.001000165939331
# 异步非阻塞-将所有异步操作放入组中,实现loop管理
class asynchronous_fetcher_4(tornado.web.RequestHandler):
    async def get(self):
        task_list = [sleep() for i in range(3)]
        task_list.append(asynchronous_fetch(url))
        body = await asyncio.wait(task_list)  # 将所有异步操作的结果返回,但是是无序的,要是需要返回结果的话解析起来比较麻烦
        print("end request:", body)
        # print(type(body), len(body),type(body[0]),len(body[0]),type(body[0]))
        self.write("%s,%s" % ([x.result() for x in body[0] if x.result() is not None][0],
                              self.request.request_time()))
# curl "127.0.0.1:8888/4"
# b'{\n  "data": "123"\n}\n',5.006999969482422
def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
        (r"/1", asynchronous_fetcher_1),
        (r"/2", asynchronous_fetcher_2),
        (r"/3", asynchronous_fetcher_3),
        (r"/4", asynchronous_fetcher_4),
        (r"/5", synchronous_fetcher),
        (r"/6", synchronous_geter),
    ], **settings)
if __name__ == "__main__":
    print("server start!")
    app = make_app()
    server = tornado.httpserver.HTTPServer(app)
    server.bind(8888)
    server.start(1)  # forks one process per cpu,windows上无法fork,这里默认为1
    tornado.ioloop.IOLoop.current().start()
总结
1.Tornado使用单线程事件循环,写的不好,会阻塞的非常严重,比如synchronous_geter
2.flask+celery可以完成常见的异步任务
3.await语法只能出现在通过async修饰的函数中
4.可以看到tornado.gen.coroutine, tornado.concurrent.run_on_executor,tornado.web.asynchronous,tornado.gen.coroutine等这些装饰器都不在经常使用了,都由async和await代替
参考文档:
https://zhuanlan.zhihu.com/p/27258289   # Python async/await入门指南
http://www.tornadoweb.org/en/stable/guide/intro.html    # 这个官网
https://www.osgeo.cn/tornado/guide/intro.html   #Tornado 1.0 - Tornado 6.0的更新说明,以及6.0版本的中文文档,适合英语不好的人阅读
https://www.osgeo.cn/tornado/releases/v5.0.0.html#  在Python 3上, IOLoop 总是包装asyncio事件循环。
On Python 3, IOLoop is always a wrapper around the asyncio event loop.
这是我重新复习tornado的原因,tornado放弃了之前自己实现的tornado.ioloop,全面拥抱asyncio的event_loop.这个改动是非常大的,
而且阅读tornado的源码可以发现其中大部分函数都支持了类型检验,和返回值提示,值得阅读.
tornado6与python3.7,异步新姿势的更多相关文章
- Python一键转Jar包,Java调用Python新姿势!
		
粉丝朋友们,不知道大家看故事看腻了没(要是没腻可一定留言告诉我^_^),今天这篇文章换换口味,正经的来写写技术文.言归正传,咱们开始吧! 本文结构: 需求背景 进击的Python Java和Pytho ...
 - 【转+自己研究】新姿势之Docker Remote API未授权访问漏洞分析和利用
		
0x00 概述 最近提交了一些关于 docker remote api 未授权访问导致代码泄露.获取服务器root权限的漏洞,造成的影响都比较严重,比如 新姿势之获取果壳全站代码和多台机器root权限 ...
 - FJNU 1159 Fat Brother’s new way(胖哥的新姿势)
		
FJNU 1159 Fat Brother’s new way(胖哥的新姿势) Time Limit: 1000MS Memory Limit: 257792K [Description] [题目 ...
 - 相比于python2.6,python3.0的新特性。
		
这篇文章主要介绍了相比于python2.6,python3.0的新特性.更详细的介绍请参见python3.0的文档. Common Stumbling Blocks 本段简单的列出容易使人出错的变动. ...
 - Broadcom BCM94352z/DW1560驱动新姿势
		
转自:https://blog.daliansky.net/Broadcom-BCM94352z-DW1560-drive-new-posture.html Broadcom WiFi/BlueToo ...
 - vue组件通信新姿势
		
在vue项目实际开发中我们经常会使用props和emit来进行子父组件的传值通信,父组件向子组件传递数据是通过prop传递的, 子组件传递数据给父组件是通过$emit触发事件来做到的.例如: Vue. ...
 - JSON CSRF新姿势
		
以前做渗透测试,遇到过很多次POST数据为JSON数据的CSRF,一直没有搞定,最近发现一个新姿势, 本文作者:Mannix@安全文库 微信公众号:安全文库 测试的时候,当应用程序验证了Cont ...
 - bzoj1656: [Usaco2006 Jan] The Grove 树木 (bfs+新姿势)
		
题目大意:一个n*m的图中,“.”可走,“X”不可走,“*”为起点,问从起点开始绕所有X一圈回到起点最少需要走多少步. 一开始看到这题,自己脑洞了下怎么写,应该是可过,然后跑去看了题解,又学会了一 ...
 - Java计时新姿势
		
为获得更好的阅读体验,请访问原文:传送门 前言: 最近公司来了个大佬,从他那里学到不少东西,其中一个就是计时 的新姿势「StopWatch」,赶紧来一起了解了解吧! 一.最简单的计时 在我们的程序中不 ...
 
随机推荐
- JPA笔记4 ManyToMany
			
package many_to_many; import java.util.HashSet; import java.util.Set; import javax.persistence.Entit ...
 - react-custom-scrollbars的使用
			
react-custom-scrollbars的作用 流畅的本机浏览器滚动 移动设备的本机滚动条 完全可定制 自动隐藏 自动高度 通用(在客户端和服务器上运行) requestAnimationFra ...
 - 转   Fortofy扫描漏洞解决方案
			
Log Forging漏洞: 数据从一个不可信赖的数据源进入应用程序. 在这种情况下,数据经由CreditCompanyController.java 的第 53行进入 getParameter(). ...
 - android studio学习----自动导包
			
介绍一个最有用的设置,我们只有每次引用一些类的时候必须要导包,而Studio可以通过设置自动导包,简直太实用了. 到 Preferences -> Editor -> Auto Impor ...
 - PMP备考-第二章-项目运行环境与项目经理
			
组织系统的三大因素:组织治理框架,管理要素和组织结构 组织治理和项目治理 组织治理 :组织中的重要决策制定框架,谁有权在什么时候用什么发放做出并推行什么重要决策. 项目治理 :组织为项目建立的高级别的 ...
 - 理解Java方法增强
			
在实际开发中,我们往往需要对某些方法进行增强,常用的方法增强的方式有三种. 类继承 .方法覆盖 必须控制对象创建,才能使用该方式 装饰者模式方法加强 必须和目标对象实现相同接口或继续相同父类,特殊构造 ...
 - AI 的架构与核心
			
AI 的架构 人工智能的架构分为三层:应用层.技术层和基础层. 应用层聚焦在人工智能和各行业各领域的结合.技术层是算法.模型和技术开发.基础层则是计算能力和数据资源. 数据收集:获取什么类型的数据,数 ...
 - du查看某个文件或目录占用磁盘空间的大小
			
一.du的功能:`du` reports the amount of disk space used by the specified files and for each subdirectory ...
 - Promise的三兄弟:all(), race()以及allSettled()
			
摘要: 玩转Promise. 原文:Promise 中的三兄弟 .all(), .race(), .allSettled() 译者:前端小智 Fundebug经授权转载,版权归原作者所有. 从ES6 ...
 - linux 互斥锁和条件变量
			
为什么有条件变量? 请参看一个线程等待某种事件发生 注意:本文是linux c版本的条件变量和互斥锁(mutex),不是C++的. mutex : mutual exclusion(相互排斥) 1,互 ...