如何定义/创建协程

只要在一个函数前面加上 async 关键字,这个函数对象是一个协程,通过isinstance函数,它确实是Coroutine类型。

from collections.abc import Coroutine

async def hello(name):
print('Hello,', name) if __name__ == '__main__':
# 生成协程对象,并不会运行函数内的代码
coroutine = hello("World") # 检查是否是协程 Coroutine 类型
print(isinstance(coroutine, Coroutine)) # True

生成器是协程的基础,那我们是不是有办法,将一个生成器,直接变成协程使用呢。答案是有的。

import asyncio
from collections.abc import Generator, Coroutine '''
只要在一个生成器函数头部用上 @asyncio.coroutine 装饰器
就能将这个函数对象,【标记】为协程对象。注意这里是【标记】,划重点。
实际上,它的本质还是一个生成器。
标记后,它实际上已经可以当成协程使用。后面会介绍。
''' @asyncio.coroutine
def hello():
# 异步调用asyncio.sleep(1):
yield from asyncio.sleep(1) if __name__ == '__main__':
coroutine = hello()
print(isinstance(coroutine, Generator)) # True
print(isinstance(coroutine, Coroutine)) # False

asyncio的几个概念

在了解asyncio的使用方法前,首先有必要先介绍一下,这几个贯穿始终的概念。

  • event_loop 事件循环:程序开启一个无限的循环,程序员会把一些函数(协程)注册到事件循环上。当满足事件发生的时候,调用相应的协程函数。
  • coroutine 协程:协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用。
  • future 对象: 代表将来执行或没有执行的任务的结果。它和task上没有本质的区别
  • task 任务:一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含任务的各种状态。Task 对象是 Future 的子类,它将 coroutine 和 Future 联系在一起,将 coroutine 封装成一个 Future 对象。
  • async/await 关键字:python3.5 用于定义协程的关键字,async定义一个协程,await用于挂起阻塞的异步调用接口。其作用在一定程度上类似于yield。

学习协程是如何工作的

协程完整的工作流程是这样的

  • 定义/创建协程对象
  • 将协程转为task任务
  • 定义事件循环对象容器
  • 将task任务扔进事件循环对象中触发
import asyncio

async def hello(name):
print('Hello,', name) # 定义协程对象
coroutine = hello("World") # 定义事件循环对象容器
loop = asyncio.get_event_loop()
# task = asyncio.ensure_future(coroutine) # 将协程转为task任务
task = loop.create_task(coroutine) # 将task任务扔进事件循环对象中并触发
loop.run_until_complete(task) 输出结果:
Hello, World

await与yield对比

前面我们说,await用于挂起阻塞的异步调用接口。其作用在一定程度上类似于yield。

注意这里是,一定程度上,意思是效果上一样(都能实现暂停的效果),但是功能上却不兼容。就是你不能在生成器中使用await,也不能在async 定义的协程中使用yield。

普通函数中 不能使用 await

async 中 不能使用yield

除此之外呢,还有一点很重要的。

  • yield from 后面可接 可迭代对象,也可接future对象/协程对象;
  • await 后面必须要接 future对象/协程对象

如何验证呢?

yield from 后面可接 可迭代对象,这个前两章已经说过了,这里不再赘述。
接下来,就只要验证,yield from和await都可以接future对象/协程对象就可以了。

验证之前呢,要先介绍一下这个函数:
asyncio.sleep(n),这货是asyncio自带的工具函数,他可以模拟IO阻塞,他返回的是一个协程对象。

func = asyncio.sleep(2)
print(isinstance(func, Future)) # False
print(isinstance(func, Coroutine)) # True

还有,要学习如何创建Future对象,不然怎么验证。
前面概念里说过,Task是Future的子类,这么说,我们只要创建一个task对象即可。

import asyncio
from asyncio.futures import Future async def hello(name):
await asyncio.sleep(2)
print('Hello, ', name) coroutine = hello("World") # 将协程转为task对象
task = asyncio.ensure_future(coroutine) print(isinstance(task, Future)) # True

绑定回调函数

异步IO的实现原理,就是在IO高的地方挂起,等IO结束后,再继续执行。在绝大部分时候,我们后续的代码的执行是需要依赖IO的返回值的,这就要用到回调了。

回调的实现,有两种,一种是绝大部分程序员喜欢的,利用的同步编程实现的回调。
这就要求我们要能够有办法取得协程的await的返回值。

import asyncio
import time async def _sleep(x):
time.sleep(2)
return '暂停了{}秒!'.format(x) coroutine = _sleep(2)
loop = asyncio.get_event_loop() task = asyncio.ensure_future(coroutine)
loop.run_until_complete(task) # task.result() 可以取得返回结果
print('返回结果:{}'.format(task.result())) 输出:
返回结果:暂停了2秒!

还有一种是通过asyncio自带的添加回调函数功能来实现。

import time
import asyncio async def _sleep(x):
time.sleep(2)
return '暂停了{}秒!'.format(x) def callback(future):
print('这里是回调函数,获取返回结果是:', future.result()) coroutine = _sleep(2)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(coroutine) # 添加回调函数
task.add_done_callback(callback) loop.run_until_complete(task) 输出:
这里是回调函数,获取返回结果是: 暂停了2秒!

出处:https://www.cnblogs.com/wongbingming/p/9095243.html

IO框架:asyncio 上篇的更多相关文章

  1. 爬虫之多线程 多进程 自定义异步IO框架

    什么是进程? 进程是程序运行的实例,是系统进行资源分配和调度的一个独立单位,它包括独立的地址空间,资源以及1个或多个线程. 什么是线程? 线程可以看成是轻量级的进程,是CPU调度和分派的基本单位. 进 ...

  2. Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(上篇——纯前端多页面)

    Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(上篇--纯前端多页面) @(HTML/JS) 一般来说,使用vue做成单页应用比较好,但特殊情况下,需要使用多页面也有另外 ...

  3. socket.io框架

    socket.io框架 一.问题背景 目前公司在互联网产品上需要程序与前端部分要进行一个实时交互,在进行一定程度上的选型后,决定使用socket.io框架进行一个实践,算是公司的一个新的 尝试,也算是 ...

  4. (转)Python黑魔法 --- 异步IO( asyncio) 协程

    转自:http://www.jianshu.com/p/b5e347b3a17c?from=timeline Python黑魔法 --- 异步IO( asyncio) 协程 作者 人世间 关注 201 ...

  5. java IO框架分析

    jave.io框架 2010-11-10 22:18:34|  分类: 默认分类|举报|字号 订阅     可从IO的类层次,IO框架的设计模式来论述. 总体来说,IO可以分为字节流和字符流,不同在于 ...

  6. Python并发编程之初识异步IO框架:asyncio 上篇(九)

    大家好,并发编程 进入第九篇. 通过前两节的铺垫(关于协程的使用),今天我们终于可以来介绍我们整个系列的重点 -- asyncio. asyncio是Python 3.4版本引入的标准库,直接内置了对 ...

  7. Python并发编程之学习异步IO框架:asyncio 中篇(十)

    大家好,并发编程 进入第十章.好了,今天的内容其实还挺多的,我准备了三天,到今天才整理完毕.希望大家看完,有所收获的,能给小明一个赞.这就是对小明最大的鼓励了.为了更好地衔接这一节,我们先来回顾一下上 ...

  8. 异步IO框架:asyncio 中篇

    上一节我们首先介绍了,如何创建一个协程对象.主要有两种方法 通过async关键字, 通过@asyncio.coroutine 装饰函数. 然后有了协程对象,就需要一个事件循环容器来运行我们的协程.其主 ...

  9. Python并发编程之实战异步IO框架:asyncio 下篇(十一)

    大家好,并发编程 进入第十一章. 前面两节,我们讲了协程中的单任务和多任务 这节我们将通过一个小实战,来对这些内容进行巩固. 在实战中,将会用到以下知识点: 多线程的基本使用 Queue消息队列的使用 ...

随机推荐

  1. DP,数论————洛谷P4317 花神的数论题(求1~n二进制中1的个数和)

    玄学代码(是洛谷题解里的一位dalao小粉兔写的) //数位DP(二进制)计算出f[i]为恰好有i个的方案数. //答案为∏(i^f[i]),快速幂解决. #include<bits/stdc+ ...

  2. 第五周课程总结&实验报告(四)

    第五周课程总结 本周主要学习了 1.抽象类 抽象类的定义格式 abstract class抽象类名称{ 属性; 访问权限返回值类型方法名称(参数){ //普通方法 [return返回值]; } 访问权 ...

  3. [转帖]查看Linux用的桌面是GNOME、KDE或者其他

    http://superuser.com/questions/96151/how-do-i-check-whether-i-am-using-kde-or-gnome KDE 基于QT做的 已经越来越 ...

  4. SQLServer学习之表的操作

    SQLServer学习之表的操作 关系数据库通常包含多个表.数据库实际上是表的集合,数据库的数据或者信息都是存储在表中的.表是对数据进行存储和操作的一种逻辑结构,每一个表都代表一个对用户意义的对象. ...

  5. Python—None

    None是一个特殊的常量. None不是False. None不是0. None不是空字符串. None有自己的数据类型NoneType,并且是NoneType中唯一的值. None只是一个空值的对象 ...

  6. 【xlwings】 wps 和 office 的excel creat_sheet区别

    最近在学习 xlwings,参考学习的网址:https://www.jianshu.com/p/b534e0d465f7 写得很棒,学到了很多. 在新建sheet表单, 发现一个问题. import ...

  7. LeetCode 142——环形链表II(JAVA)

    给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 - ...

  8. echart4数据管理组件dataset学习

    背景 如果后台数据固定,如何动态定制其前端数据展示方式呢?也就是说同一种数据,如何被多个前端Echarts图表复用呢?最近在研究一种数据展示可配置化的功能,然后发现了echart4.0的dataset ...

  9. T100——r类 凭证报表 打印

    报表开发流程:1.建立入口程序 如r类的作业:cxmr500步骤: azzi900中建立程序代号 azzi910中建立作业代号 设计器--规格--签出 设计器--程序--签出 adzp168(r.a) ...

  10. Unity鼠标移动到物体上显示信息

    相信大家玩游戏的时候,鼠标移动到游戏装备上,都会显示装备的的具体信息,那么接下来就写代码把,废话不多说. 下面是 效果图 鼠标移动到装备位置显示的信息,鼠标移动不在装备区域后不现实信息,下面是代码 : ...