如何定义/创建协程

只要在一个函数前面加上 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 fromawait都可以接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. Java学习笔记-IO

    IO(Input Output)流,用来处理设备之间的数据传输 IO IO概述 Java对数据的操作是通过流的方式 Java用于操作流的对象都在IO包中 流按操作数据分为两种:字节流与字符流 流按流向 ...

  2. 关于js中this指向的问题

    this的绑定规则有4种 默认绑定 隐性绑定 显性绑定 new绑定 this绑定优先级 new 绑定 > 显性绑定 > 隐性绑定 > 默认绑定 1.如果函数被new 修饰 this绑 ...

  3. Windows主机SAM文件格式破解解密

    文件格式如是下图这种格式: 那么就可以通过通过kali终端samdump2 + system + sam 生成出来通过hashcat -m 1000去跑,或者通过md5查询

  4. linux系统设置允许密码登录

    编辑  /etc/ssh/sshd_config 文件 将PasswordAuthentication 的值改为 yes 然后重启ssh 服务 进入到  /etc/init.d 文件夹内 执行 ./s ...

  5. Linux就该这么学——初识vim编辑器

    在Linux系统中一切都是文件,而配置一个服务就是在修改其配置文件的参数 初识Vim编辑器 Vim编辑器顾名思义就是用来编写脚本程序的”记事本” Vim编辑器模式 : 命令模式 : 控制光标移动,可对 ...

  6. python基础知识0-5(单双向队列)

    #多项队列import collections #导入模块d = collections.deque() #deque方法d.append('1') #添加元素d.appendleft('2')d.a ...

  7. DevOps 之 Jenkins 安装、配置、美化、插件及常见错误处理

    继续上一篇的话题,既然已经搭建了 GitLab 的代码仓库,那么现在就可以开始进行下一步持续集成环境的搭建了.公司准备利用 Jenkins CI 进行持续集成,本文记录了 Jenkins 的安装.基础 ...

  8. 在Window Server 2016中使用Web Deploy方式发布.NET Web应用

    1.在IIS里面点击获取新的Web平台组件 2.下载Web平台组件并安装 3.在其中搜索Web Deploy,找到3.5版本,并安装 4.继续搜索Web Deploy 3.6版本,并安装 安装好之后, ...

  9. 9.bash历史的交互使用

    9.历史的交互使用本章从用户的角度介绍了如何使用 GNU 的历史库功能.可以把这里的内容作为用户指南.关于如何在其它程序中使用 GNU 的历史库功能,请参考<GNU Readline 库参考手册 ...

  10. WPF 键盘事件

    private void Window_KeyDown(object sender, KeyEventArgs e) { if (e.KeyStates==Keyboard.GetKeyStates( ...