python asyncio教程_Python 协程模块 asyncio 使用指南

Python 协程模块 asyncio 使用指南

前面我们通过5 分钟入门 Python 协程了解了什么是协程,协程的优点和缺点和如何在 Python 中实现一个协程。没有看过的同学建议去看看。这篇文章,将不再对理论性的东西做过多的解说。而是倾向于 asyncio 的使用上,另外为了保证文章时效性这里我们使用 Python3.8 来进行对后面内容的操作。

协程的演变

其实早在 Python3.4 的时候就有协程,当时的协程是通过 @asyncio.coroutine 和 yeild from 实现的。在一些很老教程中你可能看到的是下面这种形式:

import asyncio

@asyncio.coroutine

def print_hello():

print("Hello world!")

r = yield from asyncio.sleep(1)

print("Hello again!")

# 创建并获取EventLoop:

loop = asyncio.get_event_loop()

# 执行协程

loop.run_until_complete(print_hello())

loop.close()

因为现在几乎没有人这样写了所以仅作为了解即可。

然后到了 Python3.5 引入了 async/await 语法糖,一直到现在Python3.8 都是用这种形式来表示协程,示例如下。

import asyncio

async def print_hello():

print("Hello world!")

await asyncio.sleep(1)

print("Hello again!")

if __name__ == '__main__':

loop = asyncio.get_event_loop()

try:

print("开始运行协程")

coro = print_hello()

print("进入事件循环")

loop.run_until_complete(coro)

finally:

print("关闭事件循环")

loop.close()

这种是目前应用范围最广的,可以看到比之前的代码舒服了不少,不用再使用装饰器的形式了。然后就到了 Python3.7 和 Python3.8 ,协程发生了很多细小的变化,但是最大的一个变化就是,启动协程的方法变简单了,一句就可以搞定,不用再像上面那样创建循环然后再仍到事件循环去执行了。

import asyncio

async def print_hello():

print("Hello world!")

await asyncio.sleep(1)

print("Hello again!")

if __name__ == '__main__':

print("开始运行协程")

asyncio.run(print_hello())

print("进入事件循环")

怎么样是不是代码更少了,启动协程更简单了。所以这也正是我们使用 3.8 作为本教程的 Python 版,与时俱进嘛。

Asyncio 的组成部分

根据目前的官方文档,总的来说分为了两部分:高层级 API 和低层级API。

首先看高层级 API 也是接下来重点要讲的。

高层级API

协程对象和 Tasks 对象

数据流

同步源语

子进程

队列

异常

低层级API

事件循环

Futures 对象

传输和协议

策略

平台支持

上面列出了这么多的项目我们怎么去选择自己所需要的呢,总的来说对于刚入门的新手或者只是写一个自己用的程序一般都只会用到高级 API 的部分,这部分就属于开箱即用的那种,对于高级用户比如框架开发者,往往可以需要去适应各种需要,需要重新改写一些内部的结构,这个时候就需要用到低层级的 API,但是这两个层级呢只能是一个大概方向吧,主要是方便 API 的查看,下面呢我将围绕者高层级API和低层级API在日常实际工作中经常用到的内容做一些讲解。

了解几个概念

在学习 asyncio 之前需要知道这样的几个概念。

事件循环

事件循环是一种处理多并发量的有效方式,在维基百科中它被描述为「一种等待程序分配事件或消息的编程架构」,我们可以定义事件循环来简化使用轮询方法来监控事件,通俗的说法就是「当A发生时,执行B」。所谓的事件,其实就是函数。事件循环,就是有一个队列,里面存放着一堆函数,从第一个函数开始执行,在函数执行的过程中,可能会有新的函数继续加入到这个队列中。一直到队列中所有的函数被执行完毕,并且再也不会有新的函数被添加到这个队列中,程序就结束了。

Future

Future 是一个数据结构,表示还未完成的工作结果。事件循环可以监视Future 对象是否完成。从而允许应用的一部分等待另一部分完成一些工作。

简答说,Future 就是一个类,用生成器实现了回调。

Task

Task 是 Future 的一个子类,它知道如何包装和管理一个协程的执行。任务所需的资源可用时,事件循环会调度任务允许,并生成一个结果,从而可以由其他协程消费。一般操作最多的还是 Task。用Task来封装协程,给原本没有状态的协程增加一些状态。

awaitable objects(可等待对象)

如果一个对象可以用在 wait 表达式中,那么它就是一个可等待的对象。在 asyncio 模块中会一直提到这个概念,其中协程函数,Task,Future 都是 awaitable 对象。

用于 await 表达式中的对象。可以是的 coroutine 也可以是实现了 _await_() 方法的对象,参见 PEP 492。类比于 Iterable 对象是 Generator 或实现了_iter_() 方法的对象。

object._await_(self)

必须返回生成器,asyncio.Future 类也实现了该方法,用于兼容 await 表达式。

而 Task 继承自 Future,因此 awaitable 对象有三种:coroutines、Tasks 和 Futures。

await 的目的:

获取协程的结果

挂起当前协程,将控制交由事件循环,切换到其他协程,然后等待结果,最后恢复协程继续执行

启动一个协程

现在我们使用 async/await 语法来声明一个协程。 代码如下

import asyncio

async def main():

print('hello')

await asyncio.sleep(1)

print('world')

if __name__ == '__main__':

asyncio.run(main())

asyncio.run 只能用来启动程序入口协程,反过来你在程序中如果使用asyncio.run 就会出错,直接我们提到对于其他的协程通过await链来实现,这里也是一样的。下面说下代码的含义,首先启动 main 这个协程,main 方法就是先打印 hello,然后在打印过程中通过使用 asyncio.sleep 来等待1秒,之后再打印 world。前面我们提到用协程就意味着我们要一直使用非阻塞的代码,才能达到速度提升,所以这里我们用了非阻塞版的 time.sleep 即 asyncio.sleep 。

协程中调用协程

之前我们提到了在协程中,可以使用 await 来调用一

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值