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

. 本文目录#

  • 如何定义/创建协程
  • asyncio的几个概念
  • 学习协程是如何工作的
  • await与yield对比
  • 绑定回调函数

. 如何定义/创建协程#

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

  1. from collections.abc import Coroutine
  2.  
  3. async def hello(name):
  4. print('Hello,', name)
  5.  
  6. if __name__ == '__main__':
  7. # 生成协程对象,并不会运行函数内的代码
  8. coroutine = hello("World")
  9.  
  10. # 检查是否是协程 Coroutine 类型
  11. print(isinstance(coroutine, Coroutine)) # True

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

  1. import asyncio
  2. from collections.abc import Generator, Coroutine
  3.  
  4. '''
  5. 只要在一个生成器函数头部用上 @asyncio.coroutine 装饰器
  6. 就能将这个函数对象,【标记】为协程对象。注意这里是【标记】,划重点。
  7. 实际上,它的本质还是一个生成器。
  8. 标记后,它实际上已经可以当成协程使用。后面会介绍。
  9. '''
  10.  
  11. @asyncio.coroutine
  12. def hello():
  13. # 异步调用asyncio.sleep(1):
  14. yield from asyncio.sleep(1)
  15.  
  16. if __name__ == '__main__':
  17. coroutine = hello()
  18. print(isinstance(coroutine, Generator)) # True
  19. 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任务扔进事件循环对象中触发
  1. import asyncio
  2.  
  3. async def hello(name):
  4. print('Hello,', name)
  5.  
  6. # 定义协程对象
  7. coroutine = hello("World")
  8.  
  9. # 定义事件循环对象容器
  10. loop = asyncio.get_event_loop()
  11. # task = asyncio.ensure_future(coroutine)
  12.  
  13. # 将协程转为task任务
  14. task = loop.create_task(coroutine)
  15.  
  16. # 将task任务扔进事件循环对象中并触发
  17. loop.run_until_complete(task)

输出结果,当然显而易见

  1. Hello, World

. await与yield对比#

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

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

小明不是胡说八道的。有实锤。

  1. 普通函数中 不能使用 await
    再来一锤。
    async 不能使用yield

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

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

如何验证呢?

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

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

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

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

  1. import asyncio
  2. from asyncio.futures import Future
  3.  
  4. async def hello(name):
  5. await asyncio.sleep(2)
  6. print('Hello, ', name)
  7.  
  8. coroutine = hello("World")
  9.  
  10. # 将协程转为task对象
  11. task = asyncio.ensure_future(coroutine)
  12.  
  13. print(isinstance(task, Future)) # True

好了,接下来,开始验证。

验证通过

. 绑定回调函数#

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

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

  1. import asyncio
  2. import time
  3.  
  4. async def _sleep(x):
  5. time.sleep(2)
  6. return '暂停了{}秒!'.format(x)
  7.  
  8. coroutine = _sleep(2)
  9. loop = asyncio.get_event_loop()
  10.  
  11. task = asyncio.ensure_future(coroutine)
  12. loop.run_until_complete(task)
  13.  
  14. # task.result() 可以取得返回结果
  15. print('返回结果:{}'.format(task.result()))

输出

  1. 返回结果:暂停了2秒!

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

  1. import time
  2. import asyncio
  3.  
  4. async def _sleep(x):
  5. time.sleep(2)
  6. return '暂停了{}秒!'.format(x)
  7.  
  8. def callback(future):
  9. print('这里是回调函数,获取返回结果是:', future.result())
  10.  
  11. coroutine = _sleep(2)
  12. loop = asyncio.get_event_loop()
  13. task = asyncio.ensure_future(coroutine)
  14.  
  15. # 添加回调函数
  16. task.add_done_callback(callback)
  17.  
  18. loop.run_until_complete(task)

输出

  1. 这里是回调函数,获取返回结果是: 暂停了2秒!

emmm,和上面的结果是一样的。nice

python 并发专题(十三):asyncio (一) 初识的更多相关文章

  1. python并发编程之asyncio协程(三)

    协程实现了在单线程下的并发,每个协程共享线程的几乎所有的资源,除了协程自己私有的上下文栈:协程的切换属于程序级别的切换,对于操作系统来说是无感知的,因此切换速度更快.开销更小.效率更高,在有多IO操作 ...

  2. Python核心技术与实战——十八|Python并发编程之Asyncio

    我们在上一章学习了Python并发编程的一种实现方法——多线程.今天,我们趁热打铁,看看Python并发编程的另一种实现方式——Asyncio.和前面协程的那章不太一样,这节课我们更加注重原理的理解. ...

  3. python 并发专题(十三):asyncio (二) 协程中的多任务

    . 本文目录# 协程中的并发 协程中的嵌套 协程中的状态 gather与wait . 协程中的并发# 协程的并发,和线程一样.举个例子来说,就好像 一个人同时吃三个馒头,咬了第一个馒头一口,就得等这口 ...

  4. python 并发专题(十四):asyncio (三)实战

    https://www.cnblogs.com/wongbingming/p/9124142.html 在实战中,将会用到以下知识点: 多线程的基本使用 Queue消息队列的使用 Redis的基本使用 ...

  5. python 并发专题(一):并发基础相关概念,术语等

    一.线程 1.概念 线程是程序执行流的最小执行单位,是行程中的实际运作单位. 进程是一个动态的过程,是一个活动的实体.简单来说,一个应用程序的运行就可以被看做是一个进程,而线程,是运行中的实际的任务执 ...

  6. python 并发专题(二):python线程以及线程池相关以及实现

    一 多线程实现 线程模块 - 多线程主要的内容:直接进行多线程操作,线程同步,带队列的多线程: Python3 通过两个标准库 _thread 和 threading 提供对线程的支持. _threa ...

  7. python 并发专题(五):离散事件仿真(事件循环生成器)

    出租车队运营仿真 创建几辆出租车,每辆车会拉几个乘客,然后回家.出租车首先驶离车库,四处徘徊,寻找乘客:拉到乘客后,行程开始:乘客下车后,继续四处徘徊. 程序解释 程序的输出示例: 创建 3 辆出租车 ...

  8. python 并发专题(四):yield以及 yield from

    一.yield python中yield的用法很像return,都是提供一个返回值,但是yield和return的最大区别在于,return一旦返回,则代码段执行结束,但是yield在返回值以后,会交 ...

  9. python 并发专题(三):进程以及进程池相关以及实现

    一.多进程实现 multiprocess.process模块 process类 Process([group [, target [, name [, args [, kwargs]]]]]),由该类 ...

随机推荐

  1. 用python复制文件夹

    用python复制文件 1. 根据文件夹的名称复制 需要复制的文件夹编号文件中,每一行表示一个编号,如下所示: > cat id.txt 1 2 3 ... > 目标文件的目录结构树如下所 ...

  2. 简易的phpexcel导出柱状图

      首先得把phpexcel扩展的源码拷贝到项目文件下 下面是代码   /** 引入最重要的PHPExcel类库的入口文件 */ require(STK_PATH.'/class/stk/PHPExc ...

  3. 商城02——dubbo框架整合_商品列表查询实现_分页

    1.   课程计划 1.服务中间件dubbo 2.SSM框架整合. 3.测试使用dubbo 4.后台系统商品列表查询功能实现. 5.监控中心的搭建 2.   功能分析 2.1. 后台系统所用的技术 框 ...

  4. Java CRC16 MODBUS校验算法实现

    /** * CRC校验算法工具类 */ public class CRCUtil { public static String getCRC(String data) { data = data.re ...

  5. SqlServer2016 startengine错误的解决方式整理

    因为某些需要,最近在安装SqlServer2016,但总是安装失败,按照网上各路大佬的解决方案都没有成功.报错提示为两个:无法获取数据库引擎句柄,无法恢复数据库引擎服务.按照网上做法,使用admini ...

  6. Spring—容器外的Bean使用依赖注入

    认识AutowireCapableBeanFactory AutowireCapableBeanFactory是在BeanFactory的基础上实现对已存在实例的管理.可以使用这个接口集成其他框架,捆 ...

  7. 分享 HT 实用技巧:实现指南针和 3D 魔方导航

    前言 三维场景时常需要一个导航标识,用来确定场景所处的方位. 一般有两种表现形式:指南针.小方盒(方位魔方). 参考一下百度百科中的 maya 界面,可以看到右上角有一个标识方位的小盒子,说的就是它: ...

  8. Spring Boot入门系列(十六)使用pagehelper实现分页功能

    之前讲了Springboot整合Mybatis,然后介绍了如何自动生成pojo实体类.mapper类和对应的mapper.xml 文件,并实现最基本的增删改查功能.接下来要说一说Mybatis 的分页 ...

  9. 【秒懂Java】【第1章_初识Java】04_学习资料

    为了学到更多的新知识,我们经常会去网上搜索各种学习资料.或者,在学习.工作过程中遇到了解决不了的问题,我们也会去网上搜索答案(比如百度.谷歌一下).这篇文章,主要想跟大家聊聊关于学习资料的选择. 建议 ...

  10. postman无法正常启动

    想请教下各位大神,我电脑的postman打开之后就一直转,没法启动是怎么回事?重装了不同版本的也是同样的情况,重启电脑也没用...同样的安装包,在别的电脑上就能正常打开!有什么办法解决吗?  0 20 ...