IO框架:asyncio 上篇

如何定义/创建协程

只要在一个函数前面加上 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

原文地址:https://www.cnblogs.com/miaoweiye/p/12021622.html

时间: 2024-10-05 03:00:41

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

IO框架

java io简介 java io系统的设计初衷,就是为了实现"文件.控制台.网络设备"这些io设置的通信.例如,对于一个文件,我们可以打开文件,然后进行读取和写入. 在java 1.0中,java提供的类都是以字节(byte)为单位,例如,FileInputStream和FileOutputStream.而到了java 1.1,为了与国际化进行接轨,在java io中添加了许多以字符(Unicode)为单位进行操作的类. 在java io的称呼中,我们经常会提到"输入流&q

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

Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(上篇--纯前端多页面) @(HTML/JS) 一般来说,使用vue做成单页应用比较好,但特殊情况下,需要使用多页面也有另外的好处.例如手Q的多webview架构,新开页面有利于ios右划返回,也避免了返回时页面的刷新. 所以,这里我们探讨一下如何配置实现多页面的项目框架.这里是开篇,先以最简单的纯前端多页面为例入手,最终目标是完成Node.js多页面直出+前后端同构的架构. 本文源代码:https://github.c

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

大家好,并发编程 进入第十章.好了,今天的内容其实还挺多的,我准备了三天,到今天才整理完毕.希望大家看完,有所收获的,能给小明一个赞.这就是对小明最大的鼓励了.为了更好地衔接这一节,我们先来回顾一下上一节的内容. 上一节「」,我们首先介绍了,如何创建一个协程对象.主要有两种方法 通过async关键字, 通过@asyncio.coroutine 装饰函数. 然后有了协程对象,就需要一个事件循环容器来运行我们的协程.其主要的步骤有如下几点: 将协程对象转为task任务对象 定义一个事件循环对象容器用

异步IO框架:asyncio 中篇

上一节我们首先介绍了,如何创建一个协程对象.主要有两种方法 通过async关键字, 通过@asyncio.coroutine 装饰函数. 然后有了协程对象,就需要一个事件循环容器来运行我们的协程.其主要的步骤有如下几点: 将协程对象转为task任务对象 定义一个事件循环对象容器用来存放task 将task任务扔进事件循环对象中并触发 上一节,其实就只是讲了协程中的单任务,我们就来看下,协程中的多任务. 协程中的并发 协程的并发,和线程一样.举个例子来说,就好像 一个人同时吃三个馒头,咬了第一个馒

Java基础之IO框架

一.流的概念 流(stream)的概念源于UNIX中管道(pipe)的概念.在UNIX中,管道是一条不间断的字节流,用来实现程序或进程间的通信,或读写外围设备.外部文件等.       一个流,必有源端和目的端,它们可以是计算机内存的某些区域,也可以是磁盘文件,甚至可以是Internet上的某个URL.        流的方向是重要的,根据流的方向,流可分为两类:输入流和输出流.用户可以从输入流中读取信息,但不能写它.相反,对输出流,只能往输入流写,而不能读它.       实际上,流的源端和目

Python高级编程 面向对象、元类、多线程、异步IO、asyncio

—— 面向对象 —— 鸭子类型抽象基类类变量.对象变量的查找顺序静态方法.类方法.实例方法数据封装和私有属性对象的自省机制上下文管理器contextlib实现上下文管理器super函数的查找顺序mixin继承模式的应用 —— asyncio并发编程 —— 事件循环协程嵌套call_soon.call_later.call_atcall_soon_threadsafeThreadPoolExecutor+asyncioasyncio 模拟 http 请求future 和 taskasyncio 同

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

https://www.jianshu.com/p/b5e347b3a17c python asyncio 网络模型有很多中,为了实现高并发也有很多方案,多线程,多进程.无论多线程和多进程,IO的调度更多取决于系统,而协程的方式,调度来自用户,用户可以在函数中yield一个状态.使用协程可以实现高效的并发任务.Python的在3.4中引入了协程的概念,可是这个还是以生成器对象为基础,3.5则确定了协程的语法.下面将简单介绍asyncio的使用.实现协程的不仅仅是asyncio,tornado和g

自定义异步IO框架

异步就是回调 异步 = 非阻塞+循环 select只能完成IO多路复用,不能完成异步 IO多路复用--->监听多个socket对象,这个过程是同步的 利用其特性可以开发异步模块 异步IO:非阻塞的socket + IO多路复用 自定义异步框架 import socket import select class HttpRequest(object): def __init__(self, sk, host, callback): self.socket = sk self.host = host

超级快的python vibora.io框架

https://vibora.io/ Vibora代表葡萄牙语的viper,它是一个异步的客户端/服务器框架,要成为最快的Python HTTP客户端/服务器框架,支持Python 3.6+以上版本! 该框架效率高,性能好.它的API灵感来自Flask,而其内置功能基于众多著名的库,如jinja2,marshmallow,aaugustin的websockets,werkzeug等等. 为什么异步?正如其官方所提到的,“Web API通常是基于I/O的,而这正是异步架构的优势所在.” Vibor