Coroutines

asyncio在3.4版本添加到Python中,但通过async defawait关键字创建coroutines的语法是3.5才加入的,在这之前,人们把generators当作coroutines来使用,在一些老的语法中,你可以看到用@asyncio.coroutine之类的装饰器加yield的句式,在本文中,请摒弃过去的写法。

async def关键字

>>> async def f():    # 1
...     return 123
>>> type(f)    # 2
<class 'function'>
>>> import inspect    # 3
>>> inspect.iscoroutinefunction(f)
True
  1. 这是声明coroutine的最简单方式;
  2. 与生成器函数的判定一样,coroutine也会被判定为协程函数,只有在调用这个函数时才能获得协程,就如生成器一样;
  3. 标准库中的检查模块可以提供比type方法更好的内省能力。

正是由于在3.4版本用生成器当作协程来使用,所以在3.5版本中,async def的用法以及效果与生成器几乎相同。我们通过代码来观察Python如何在不同协程中切换,首先先看下如何获得return的值。

当coroutine return的时候,将会抛出一个StopIteration异常。

>>> async def f():
...     return 123
>>> coro = f()
>>> try:
...     coro.send(None)    # 1
... except StopIteration as e:
...     print('The answer was: ', e.value)    # 2
The answer was:  123
  1. coroutine通过发送None来启动,这就是loop在背后做的事;
  2. 协程返回时抛出StopIteration异常,可以通过异常的value属性访问返回值。

协程的开始和结束是通过send()和StopIteration来定义的,loop负责在背后做这些事,开发者只需要为loop安排task即可。

await关键字

await关键字总是接收一个参数,其类型必须是awaitable的,必须是如下两种之一:
1. 一个coroutine;
2. 一个实现了__await__()方法的对象,这个方法必须返回一个迭代器。

async def f():
    await asyncio.sleep(1.0)
    return 123
async def main():
    result = await f()  # 1
    return result
  1. 这里调用了f函数返回了一个coroutine。

在开始学习loop之前,了解一下如何向协程提供异常很有用,异常通常用于取消协程,在task.cancel()时,loop在内部使用coro.throw()来抛出一个asyncio.CancelledError

>>> coro = f()  # 使用上面的协程
>>> coro.send(None)
<Future pending>
>>> coro.throw(Exception, 'hello')  # 通过throw方法提供一个异常和值,该异常将在await处产生
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f
Exception: hello
>>> async def f():
...     try:
...             while True: await asyncio.sleep(0)
...     except asyncio.CancelledError:
...             print('I was cancelled!')
...     else:
...             return 111
>>> coro = f()
>>> coro.send(None)
>>> coro.send(None)
>>> coro.throw(asyncio.CancelledError)
I was cancelled!
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration   # 正是由于内部捕捉了CancelledError,这个协程得以正常退出
>>> import asyncio
>>> async def f():
...     try:
...             while True: await asyncio.sleep(0)
...     except asyncio.CancelledError:
...             print('Cancelled')
...             while True: await asyncio.sleep(0)  # 跳转到另一个协程上去了
...     else: return 1
>>> coro = f()
>>> coro.send(None)
>>> coro.throw(asyncio.CancelledError)
Cancelled
>>> coro.send(None)

目前为止的代码中,都是通过手动调用send(None)throw(asyncio.CancelledError)来模拟loop的,下一章开始学习用loop来自动处理。

>>> async def f():
...     await asyncio.sleep(0)
...     return 123
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(f())
123

深入Asyncio(四)Coroutines的更多相关文章

  1. asyncio之Coroutines,Tasks and Future

    asyncio之Coroutines,Tasks and Future Coroutines and Tasks属于High-level APIs,也就是高级层的api. 本节概述用于协程和任务的高级 ...

  2. Python标准模块--asyncio

    1 模块简介 asyncio模块作为一个临时的库,在Python 3.4版本中加入.这意味着,asyncio模块可能做不到向后兼容甚至在后续的Python版本中被删除.根据Python官方文档,asy ...

  3. 【译】深入理解python3.4中Asyncio库与Node.js的异步IO机制

    转载自http://xidui.github.io/2015/10/29/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3python3-4-Asyncio%E5%BA%93% ...

  4. Understanding Asynchronous IO With Python 3.4's Asyncio And Node.js

    [转自]http://sahandsaba.com/understanding-asyncio-node-js-python-3-4.html Introduction I spent this su ...

  5. aiohttp/asyncio 多次请求

    #!/usr/bin/env python # -*- coding: utf-8 -*- __author__ = "Daniel Altiparmak (sixfinger78@gmai ...

  6. 7.Python3标准库--文件系统

    ''' Python的标准库中包含大量工具,可以处理文件系统中的文件,构造和解析文件名,还可以检查文件内容. 处理文件的第一步是要确定处理的文件的名字.Python将文件名表示为简单的字符串,另外还提 ...

  7. Python高性能HTTP客户端库requests的使用

    Python中有许多HTTP客户端.使用最广泛且最容易的是requests. 持续连接 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很 ...

  8. Python之路(第四十七篇) 协程:greenlet模块\gevent模块\asyncio模块

    一.协程介绍 协程:是单线程下的并发,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的. 协程相比于线程,最大的区别在于 ...

  9. 关于asyncio知识(四)

    一.使用 asyncio 总结 最近在公司的一些项目中开始慢慢使用python 的asyncio, 使用的过程中也是各种踩坑,遇到的问题也不少,其中有一次是内存的问题,自己也整理了遇到的问题以及解决方 ...

随机推荐

  1. EOJ Monthly 2017.12 A B C D

    // 因为是中文题面就偷一次懒不写题意啦QAQ // 各种大作业然后又要期末还不知道什么时候能补题QAQ A. 唐纳德先生和假骰子 直接模拟 #include <bits/stdc++.h> ...

  2. VIM使用技巧3

    假如有如下代码: var  foo = "method("+argument1+","+argument2+")" 任务:在每个“+”前后各 ...

  3. LeetCode OJ-- Add Binary

    https://oj.leetcode.com/problems/add-binary/ 对两个二进制字符串求和. 对于字符串 ans_str,求它的翻转. reverse(ans_str.begin ...

  4. AC日记——琪露诺 洛谷 P1725

    琪露诺 思路: 单调队列+dp: 然而劳资不会单调队列,所以,线段树水过; 来,上代码: #include <cstdio> #include <cstring> #inclu ...

  5. 搭建https本地服务器:如何得到被所有客户端认可的ssl证书

    https,作为http的加密版,作用还是很大的:能够提升网站搜索权重,让你的网站更安全,而且如果你的网站没有使用https的话,将无法作为移动设备原生应用的api接口.可见掌握为网站启用https的 ...

  6. 爬虫学习笔记(六)PyQuery模块

    PyQuery模块也是一个解析html的一个模块,它和Beautiful Soup用起来差不多,它是jquery实现的,和jquery语法差不多,会用jquery的人用起来就比较方便了. Pyquer ...

  7. A Wasserstein Distance[贪心/模拟]

    链接:https://www.nowcoder.com/acm/contest/91/A来源:牛客网 最近对抗生成网络(GAN)很火,其中有一种变体WGAN,引入了一种新的距离来提高生成图片的质量.这 ...

  8. 解决: g++: internal compiler error: Killed (program cc1plus)

    现象描述:在树莓派上用qt编译二维码显示相关的UI程序时,经常报以上错误,有时候断电重启首次编译不会报错(估计是刚上电系统占用的内存比较少) g++: internal compiler error: ...

  9. php 技术知识点汇总

    consul : 服务发现 做服务发现的框架常用的有 zookeeper eureka etcd consul zookeeper,  php中的libzookeeper PHP使用 swagger ...

  10. Atom打开大文件卡死的问题替代方案

    无解,本身是网页的框架,所以直接换回ST或者Notepad++吧.