同步异步I/O客户端

  1. from tornado.httpclient import HTTPClient,AsyncHTTPClient
  2.  
  3. def ssync_visit():
  4. http_client = HTTPClient()
  5. response = http_client.fetch('www.baidu.com') # 阻塞,直到网站请求完成
  6. print(response.body)
  7.  
  8. def hendle_response(response):
  9. print(response.body)
  10. def async_visit():
  11. http_client = AsyncHTTPClient()
  12. http_client.fetch('www.baidu.com',callback=hendle_response) # 非阻塞
  13.  
  14. async_visit()

协程

1、编写协程函数

  1. from tornado import gen # 引入协程库
  2.  
  3. from tornado.httpclient import AsyncHTTPClient
  4.  
  5. @gen.coroutine
  6. def coroutine_visit():
  7. http_client = AsyncHTTPClient()
  8. response = yield http_client.fetch('www.baidu.com')
  9. print(response.body)

2、调用协程函数

由于Tornado协程基于python的yield关键字实现,所以不能调用普通函数一样调用协程函数

协程函数可通过以下三种方式调用

  • 在本身是协程的函数内通过yield关键字调用
  • 在IOLoop尚未启动时,通过IOLoop的run_sync()函数调用
  • 在IOLoop已经启动时,通过IOLoop的spawn_callback()函数调用

  下面是一个通过协程函数调用协程函数的例子

  1. @gen.coroutine
  2. def outer_coroutine():
  3. print('开始调用另一个协程')
  4. yield coroutine_visit()
  5. print('outer_coroutine 调用结束')
  1. outer_coroutinecoroutine_visit都是协程函数,他们之间可以通过yield关键字进行调用
  2.  
  3. IOLoop Tornado的主事件循环对象,Tornado程序通过它监听外部客户端的访问请求,并执行相应的操作,当程序尚未进入IOLoopruning状态时,可以通过run_sync()函数调用协程函数,比如:
  1. from tornado import gen # 引入协程库
  2. from tornado.ioloop import IOLoop
  3. from tornado.httpclient import AsyncHTTPClient
  4.  
  5. @gen.coroutine
  6. def coroutine_visit():
  7. http_client = AsyncHTTPClient()
  8. response = yield http_client.fetch('http://www.baidu.com')
  9. print(response.body)
  10.  
  11. def func_normal():
  12. print('开始调用协程')
  13. IOLoop.current().run_sync(lambda: coroutine_visit())
  14. print('结束协程调用')
  15. func_normal()

本例中run_sync()函数将当前函数的执行进行阻塞,直到被调用的协程执行完成

Tornado 要求协程函数在IOloop的running状态才能被调用,只不过run_sync函数自动完成了启动,停止IOLoop的步骤,他的实现逻辑为:启动IOLoop-调用被lambda封装的协程函数-停止IOLoop

当tornado程序已经处于running 状态时协程的调用如下:

  1. def func_normal():
  2. print('开始调用协程')
  3. IOLoop.current().spawn_callback(coroutine_visit)
  4. print('结束协程调用')
  5. func_normal()
  1. 开始调用协程
  2. 结束协程调用

本例中spawn_callback函数不会等待被调用的协程执行完成,而协程函数将会由IOLoop在合适的时机进行调用,并且spawn_callback函数没有提供电泳返回值的方法,所以hi能用该函数调用没有返回值的协程函数

3、在协程中调用阻塞函数

在协程中直接调用阻塞函数会影响协程本身的性能,所以tornado提供了在协程中利用线程池调度阻塞函数,从而不影响协程本身继续执行的方法,实例代码如下:

  1. from concurrent.futures import ThreadPoolExecutor
  2. from tornado import gen
  3. thread_pool = ThreadPoolExecutor(2)
  4.  
  5. def mySleep(count):
  6. import time
  7. for i in range(count):
  8. time.sleep(1)
  9.  
  10. @gen.coroutine
  11. def call_backing():
  12. print('开始调用当前函数')
  13. yield thread_pool.submit(mySleep,10)
  14. print('结束调用')
  15.  
  16. call_backing()

4、在协程中的等待多个异步调用

tornado允许在协程中用一个yield关键字等待多个异步调用,只需把这些调用用列表或字典的方式传递给yield关键字即可

实例如下:

  1. from tornado import gen # 引入协程库
  2. from tornado.ioloop import IOLoop
  3. from tornado.httpclient import AsyncHTTPClient
  4.  
  5. @gen.coroutine
  6. def coroutine_visit():
  7. http_client = AsyncHTTPClient()
  8. list_response = yield [http_client.fetch('http://www.baidu.com'),
  9. http_client.fetch('http://www.sina.com'),
  10. http_client.fetch('http://www.163.com')
  11. ]
  12. for response in list_response:
  13. print(response.body)
  14.  
  15. def func_normal():
  16. print('开始调用协程')
  17. IOLoop.current().run_sync(lambda: coroutine_visit())
  18. print('结束协程调用')
  19. func_normal()

字典同理,不再演示

Tornado 网站

异步化,协程化

当大量客户端高并发请求场景出现时,需要用到两种方式改变同步的处理请求流程

  • 异步化:针对RequestHandler的处理函数使用@tornado.web.asynchronous修饰器,将默认同步机制改成异步机制
  • 协程化:针对RequestHandler的处理函数使用@tornado.gen.coroutine修饰器,将默认的同步机制还成协程机制

1、异步化

  1. from tornado import web,httpclient
  2. import tornado
  3. class MainHandler(tornado.web.RequestHandler):
  4.  
  5. @tornado.web.asynchronous
  6. def get(self):
  7. http = tornado.httpclient.AsyncHTTPClient()
  8. http.fetch('http://www.baidu.com',callback=self.on_response)
  9. def on_response(self,response):
  10. if response.error:
  11. raise tornado.web.HTTPError(500)
  12. self.write(response.body)
  13. self.finish()

用@tornado.web.asynchronous 定义HTTP访问处理函数get(),当get函数返回时对该访问的请求尚未完成,所以tornado无法发送响应给客户端,只有随后的回掉函数中的finsh函数被调用时,tornado才知道本次处理已经完成,可以发送响应给客户端

异步虽然提高了并发能力,但是编程方法更繁琐

2、协程化

tornado 协程结合同步异步的优点,

  1. import tornado.web
  2. import tornado.httpclient
  3. class MainHandler(tornado.web.RequestHandler):
  4.  
  5. @tornado.gen.coroutine
  6. def get(self):
  7. http = tornado.httpclient.AsyncHTTPClient()
  8. response = yield http.fetch('http://www.baidu.com')
  9. self.write(response.body)

用tornado.gen.coroutine装饰MainHandler的get(),post()函数

使用异步对象处理耗时操作,比如AsyncHTTPClient

调用yield关键字获取异步对象的处理结果

实践中的异步

下各项同步(阻塞)的,如果在 tornado 中按照之前的方式只用它们,就是把 tornado 的非阻塞、异步优势削减了。

  • 数据库的所有操作,不管你的数据是 SQL 还是 noSQL,connect、insert、update 等
  • 文件操作,打开,读取,写入等
  • time.sleep
  • smtplib,发邮件的操作
  • 一些网络操作,比如 tornado 的 httpclient 以及 pycurl 等

解决方法

  • 在数据库方面,由于种类繁多,不能一一说明,比如 mysql,可以使用adb模块来实现 python 的异步 mysql 库;对于 mongodb 数据库,有一个非常优秀的模块,专门用于在 tornado 和 mongodb 上实现异步操作,它就是 motor。
  • 文件操作方面也没有替代模块,只能尽量控制好 IO,或者使用内存型(Redis)及文档型(MongoDB)数据库。
  • time.sleep() 在 tornado 中有替代:yield tornado.gen.sleep() 或者tornado.ioloop.IOLoop.instance().add_timeout
  • smtp 发送邮件,推荐改为 tornado-smtp-client。
  • 对于网络操作,要使用 tornado.httpclient.AsyncHTTPClient。

greenlet-tornado 可以实现用专门的库来实现tornado 的异步而不使用装饰器的异步

Tornado 协程的更多相关文章

  1. tornado用户指引(三)------tornado协程使用和原理(二)

    Python3.5  async和await async和await是python3.5引入的2个新的关键字(用这两个关键字编写的函数也称之为"原生协程"). 从tornado4. ...

  2. tornado用户指引(二)------------tornado协程实现原理和使用(一)

    摘要:Tornado建议使用协程来实现异步调用.协程使用python的yield关键字来继续或者暂停执行,而不用编写大量的callback函数来实现.(在linux基于epoll的异步调用中,我们需要 ...

  3. tornado 协程的实现原理个人理解;

    tornado实现协程的原理主要是利用了(1)python里面的generator (2)future类和ioloop相互配合,两者之间的相互配合是通过gen.coroutine装饰器来实现的: 具体 ...

  4. tornado用户指引(四)------tornado协程使用和原理(三)

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/happyAnger6/article/details/51291221几种常用的协程方式: 1.回调 ...

  5. Python协程 Gevent Eventlet Greenlet

    https://zh.wikipedia.org/zh-cn/%E5%8D%8F%E7%A8%8B 协程可以理解为线程中的微线程,通过手动挂起函数的执行状态,在合适的时机再次激活继续运行,而不需要上下 ...

  6. 分析Tornado的协程实现

    转自:http://www.binss.me/blog/analyse-the-implement-of-coroutine-in-tornado/ 什么是协程 以下是Wiki的定义: Corouti ...

  7. 深入tornado中的协程

    tornado使用了单进程(当然也可以多进程) + 协程 + I/O多路复用的机制,解决了C10K中因为过多的线程(进程)的上下文切换 而导致的cpu资源的浪费. tornado中的I/O多路复用前面 ...

  8. python tornado TCPserver异步协程实例

    项目所用知识点 tornado socket tcpserver 协程 异步 tornado tcpserver源码抛析 在tornado的tcpserver文件中,实现了TCPServer这个类,他 ...

  9. Python开发【模块】:tornado.queues协程的队列

    协程的队列 协调生产者消费者协程. from tornado import gen from tornado.ioloop import IOLoop from tornado.queues impo ...

随机推荐

  1. [JSOI2004]平衡点

    题面在这里 题意 ...见链接吧 sol 在此发一篇模拟退火的题解 不得不说luogu的数据真是太良心啦 一句话解释模拟退火:在一个慢慢缩小的范围内随机状态寻找最优解,当转移状态更优时直接接受,当当前 ...

  2. xctf的一道题目(77777)

    这次比赛我没有参加,这是结束之后才做的题目 题目链接http://47.97.168.223:23333 根据题目信息,我们要update那个points值,那就是有很大可能这道题目是一个sql注入的 ...

  3. 利用EF Core的Join进行多表查询

    背景 话说有这么一家子,老公养了一条狗,老婆养了一只猫. 数据库的设计 人表 宠物表 通过表可以知道,宠物通过Owner指向主人的Id. 问题来了,我要和故事开头一样,老公-狗,老婆-猫,对应起来,怎 ...

  4. [转]Git教程【译】

    [转]Git教程[译] http://www.cnblogs.com/zhangjing230/archive/2012/05/09/2489745.html 原文出处:http://www.voge ...

  5. 题目1023:EXCEL排序

    //都是泪啊,搞了半天,竟然是成绩的数据类型搞成了string,输出测试用例的次数竟然搞成了排序的类别...细节决定成败!!! 题目描述: Excel可以对一组纪录按任意指定列排序.现请你编写程序实现 ...

  6. Qt下载地址

    上Qt官网http://www.qt.io/download/想下载Qt,速度很慢,在这里记录下在Qt官网看到的镜像下载地址: 1. 所有Qt版本下载地址: http://download.qt.io ...

  7. python笔记之异常

    异常 內建异常在exceptions模块内,使用dir函数列出模块的内容. 自定义异常类:继承基类Exception. 异常可以使用raise语句引发,可以使用try ... except ... e ...

  8. IPFS: BitSwap协议(数据块交换)

    原创 2018-01-11 飞向未来 IPFS指南 BitSwap协议 IPFS节点之间是如何进行数据交换的?本文来讲一下这个问题. IPFS在BitTorrent的基础上实现了p2p数据交换协议:B ...

  9. 读取pdf内容分页和全部

    //读取pdf 全部内容public static String topdffile(String pdffile){ StringBuffer result = new StringBuffer() ...

  10. 剑指Offer-按之字形顺序打印二叉树

    package Tree; import java.util.ArrayList; import java.util.LinkedList; import java.util.Queue; /** * ...