Python3.5  async和await

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

从tornado4.3开始,你可以在使用yield的tornado协程中使用这两个关键字。只需将原来用@gen.coroutine装饰的函数定义成async def func(),并将原来yield语句改为await即可。

本文的后面部分为了和老版本的python兼容将会继续使用yield关键字,但是使用async和await将会更快。

举例:

from tornado.ioloop import IOLoop
from tornado.httpclient import AsyncHTTPClient

async def fetch_coroutine():
    http_cli = AsyncHTTPClient()
    reponse = await http_cli.fetch("http://www.baidu.com")
    print(reponse.body)

IOLoop.instance().run_sync(fetch_coroutine)
yield关键字比await关键字更加通用。比如,在基于yield的协程中你可以yield一个Future的列表,但是在原生的协程中要想这么做,你必须用tornado.gen.multi来装饰Future的列表。
另外,你可以使用tornado.gen.convert_yielded来装饰任何可以用yield关键字工作的对象,这样你就可以在await中使用它们。
尽管原生的协程不与任何特定的框架绑定(比如tornado框架,原生协程也不需要额外的tornado.gen.coroutine或者asyncio.coroutine装饰器来装饰).但是不同实现的协程之间是不兼容的。
当第一个协程被调用时会选择一个协程的执行体,然后这个执行体会被通过await调用的其它协程所共享。
tornado的协程执行体被设计的十分通用,它可以接受其它任何框架的await的对象。
其它的协程实现可能有局限性(比如asyncio协程的执行体不能接受其它框架的协程)。
因此,我们建议使用tornado的协程执行体,这样你就可以在你的应用中使用不同框架的协程。
如果你已经使用了asyncio执行体来执行协程,这时你可以通过tornado.platform.asyncio.to_asyncio_future将
tornado的协程适配成可以在asyncio中执行的协程。
举例:
下面的例子演示了如何asyncio中执行tornado的协程:
注意:执行ASyncIOMainLoop().install是为了初始化ioLoop为asyncio的ioLoop.
from tornado import gen
from tornado.platform.asyncio import to_asyncio_future,AsyncIOMainLoop
from tornado.httpclient import AsyncHTTPClient
import asyncio

@gen.coroutine
def tornado_coroutine():
    cli = AsyncHTTPClient()
    response = yield cli.fetch("http://www.baidu.com")
    print(response.body)

AsyncIOMainLoop().install()
asyncio.get_event_loop().run_until_complete(to_asyncio_future(tornado_coroutine()))

tornado协程的工作原理
包含yield语句的函数是一个生成器。所有的生成器都是异步的。当我们调用生成器函数的时候,生成器函数返回一个生成器对象,而不是像普通函数那样直接执行完成。@gen.coroutine装饰器通过yield表达式来和生成器对象交互,调用@gen.coroutine装饰的函数会返回一个Future.
下面是一个coroutine装饰器内部循环的简化实现:
可以看到,coroutine装饰器内部有一个Runner对象,这个对象将我们的生成器函数包装为self.gen.
这个对象就是协程的运行体,它会在内部一直循环运行生成器,直到生成器函数阻塞返回一个Future或者结束。如果遇到yield返回的Future,便通过Future对象的结束回调函数来继续运行生成器函数。
具体实现是:
1.当生成器函数运行到yield时,会得到一个Future.为这个Future添加结束回调通知函数callback.执行体释放执行权给ioLoop继续执行其它协程。
2.当这个Future异步运行结束时,会调用callback函数。callback函数得到Future的运行结果,并将结果通过生成器的send方法发送给生成器。这样生成器函数就会在yield的地方返回Future的异步执行结果并继续运行。
3.1接着生成器函数继续运行,直到生成器函数运行结束
3.2或者遇到下一个yield转到步骤1
# Simplified inner loop of tornado.gen.Runner
def run(self):
# send(x) makes the current yield return x.
# It returns when the next yield is reached
    future = self.gen.send(self.next)
    def callback(f):
        self.next = f.result()
        self.run()
    future.add_done_callback(callback)

如何调用一个协程
协程并不以一般的方式产生异常。协程中产生的任何异常将会被Future包装起来直到它被yielded.
下面代码展示了我们函数产生的异常是如何被包装到future中的:
func为我们的函数。
try:
    result = func(*args, **kwargs)
except (Return, StopIteration) as e:
    result = _value_from_stopiteration(e)
except Exception:
    future.set_exc_info(sys.exc_info())
return future
这意味着我们必须以正确的方式调用协程,否则你可能会忽略一些发生的错误。
在大部分情况下,任何调用协程的函数本身也需要是一个协程,而且需要在调用另外一个协程的地方使用yield关键字。当你需要重写父类中的函数时,你需要翻阅相应的文档以确定函数是否允许被实现为一个协程,文档中需要说明函数需要是一个协程或者需要返回一个Future.
下面的函数修正了上面的错误,在一个协程中通过yield关键字调用divide这个协程。
@gen.coroutine
def good_call():
    # yield will unwrap the Future returned by divide() and raise
    # the exception.
    yield divide(1, 0)
有时候你仅仅是想执行一个协程并不关心其结果,这种情况建议你使用IOLoop.spawn_callback(callback, *args, **kwargs)。这样如果协程执行失败,ioLoop会将调用栈记录到log中。
# The IOLoop will catch the exception and print a stack trace in
# the logs. Note that this doesn't look like a normal call, since
# we pass the function object to be called by the IOLoop.
IOLoop.current().spawn_callback(divide, 1, 0)

最后,如果在程序顶层,ioloop还没有运行,你可以通过run_sync方法开始ioloop的运行,并执行协程。run_sync常常用来执行main协程,main里面包含了一系列的协程。

# run_sync() doesn't take arguments, so we must wrap the
# call in a lambda.
IOLoop.current().run_sync(lambda: divide(1, 0))
注意:由于run_sync只接受一个函数参数,所以你需要通过lambda表达式传递函数参数,或者通过functools.partial来将函数变为偏函数。
IOLoop.current().run_sync(functools.partial(divide,1, 0))
---------------------
作者:self-motivation
来源:CSDN
原文:https://blog.csdn.net/happyanger6/article/details/51277407
版权声明:本文为博主原创文章,转载请附上博文链接!

tornado用户指引(三)------tornado协程使用和原理(二)的更多相关文章

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

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

  2. PHP下的异步尝试三:协程的PHP版thunkify自动执行器

    PHP下的异步尝试系列 如果你还不太了解PHP下的生成器和协程,你可以根据下面目录翻阅 PHP下的异步尝试一:初识生成器 PHP下的异步尝试二:初识协程 PHP下的异步尝试三:协程的PHP版thunk ...

  3. python并发编程之进程、线程、协程的调度原理(六)

    进程.线程和协程的调度和运行原理总结. 系列文章 python并发编程之threading线程(一) python并发编程之multiprocessing进程(二) python并发编程之asynci ...

  4. GO GMP协程调度实现原理 5w字长文史上最全

    1 Runtime简介 Go语言是互联网时代的C,因为其语法简洁易学,对高并发拥有语言级别的亲和性.而且不同于虚拟机的方案.Go通过在编译时嵌入平台相关的系统指令可直接编译为对应平台的机器码,同时嵌入 ...

  5. Golang源码探索(二) 协程的实现原理

    Golang最大的特色可以说是协程(goroutine)了, 协程让本来很复杂的异步编程变得简单, 让程序员不再需要面对回调地狱, 虽然现在引入了协程的语言越来越多, 但go中的协程仍然是实现的是最彻 ...

  6. Golang源码探索(二) 协程的实现原理(转)

    Golang最大的特色可以说是协程(goroutine)了, 协程让本来很复杂的异步编程变得简单, 让程序员不再需要面对回调地狱,虽然现在引入了协程的语言越来越多, 但go中的协程仍然是实现的是最彻底 ...

  7. 深入浅出!从语义角度分析隐藏在Unity协程背后的原理

    Unity的协程使用起来比较方便,但是由于其封装和隐藏了太多细节,使其看起来比较神秘.比如协程是否是真正的异步执行?协程与线程到底是什么关系?本文将从语义角度来分析隐藏在协程背后的原理,并使用C++来 ...

  8. 协程概念,原理及实现(c++和node.js实现)

    协程 什么是协程 wikipedia 的定义: 协程是一个无优先级的子程序调度组件,允许子程序在特点的地方挂起恢复. 线程包含于进程,协程包含于线程.只要内存足够,一个线程中可以有任意多个协程,但某一 ...

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

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

随机推荐

  1. Java数字和字符串的相互转换(BigDecimal的使用)

    String s = "100."; double d1 = "1.23"; double d = Double.parseDouble(s); s = Str ...

  2. Word 2010 去除文字或段落背景色

    在复制网页文本到Word时,有时会带有网页上的背景颜色.下面采用两种方法解决这种问题,可根据不同需要进行选择. 方法一:清除样式 此种方法适用于只需要网页文字,而不想要网页任何样式信息,如字体大小,段 ...

  3. order by注入点利用方式分析

    漏洞分析 使用sqli-lab中的lesson-52作为测试目标.关键代码为: error_reporting(0); $id=$_GET['sort']; if(isset($id)) { //lo ...

  4. skype for business server 2015 报错“不可用:试图检查架构状态时发生故障,请确保能够访问Active Direcotry”

    报错“不可用:试图检查架构状态时发生故障,请确保能够访问Active Direcotry” 遇到错误后就上网查询了下,有的人说用下面方法解决了 用域的administrator 登入就可以了(之前是用 ...

  5. ES6 Map遍历、filter()筛选对象

    目录: -------- 1.map() -------- 2.filter(): ------------- 2.1.filter函数可以看成是一个过滤函数,返回符合条件的元素的数组 ------- ...

  6. windows生成硬链接

    因工作电脑需要同时使用pl/sql和toad工具需要同时配置32位和64位oracle client如此增加了维护tnsnames.ora的复杂程度使用windows硬链接可以减少工作量,每次只修改源 ...

  7. python3.6安装总结

    安装Python 3.6 过程中出现了一些问题,导致费时费力.因此把自己安装过程中出现的问题写出来,以备大家查看. 第一步:比较简单的一种安装方法是直接安装Anacanda3 python即可,这时可 ...

  8. ZT 初始化 const 成员和引用类型成员(C++)

    初始化 const 成员和引用类型成员(C++) 初始化 const 成员和引用类型成员的问题,在 C++ 教材中讲述初始化列表的章节应该都有讲过,但是因为平时用得少,所以可能有不少人没注意到.待到用 ...

  9. 《React 与 Redux 开发实例精解》出版了!

    <React 与 Redux 开发实例精解>出版了! <React 与 Redux 开发实例精解>出版了! 关于 React 与 Redux React 与 Redux, 一个 ...

  10. WiFi安全测试工具WiFiPhisher

    官方下载地址:https://github.com/sophron/wifiphisher打不开的要翻GFW好事做到底wifiphisher-master.zip=================== ...