python 协程之asyncio(一)

介绍

asyncio是用来编写并发代码的库,使用async/await语法。

asyncio被用作与多个提供高性能python异步框架的基础,包括网络和网站服务,数据库连接库,分布式任务队列等等

在实际的开发中,为了实现更高的并发有很多的方案,比如多进程、多线程。但是无论是多进程还是多线程,IO的调度更多的取决于操作系统,而协程的方式,其调度确是来自于用户,用户在函数中yield一个状态。使用协程可以实现高效的并发任务。

最简单的示例

  

复制代码
import asyncio
async def say(name):
    print(name,'hello','开始')
    await asyncio.sleep(2)
    print(name,'hello','结束')

if __name__ == '__main__':
    loop=asyncio.get_event_loop()
    loop.run_until_complete(say('jack'))
复制代码

 

基本流程

  • 通过关键字async定义一个协程对象

  • 通过await 将尚未实现完毕的程序挂起
  • 协程不能直接运行,所以要丢进事件循环loop,由loop在适当的时候调用

  • asycio.get_event_loop创建一个事件循环

  • run_until_complete注册协程到事件循环并启动

创建任务

协程对象在注册到循环事件的时候,也就是在调用run_until_complete之后将协程对象打包成一个任务对象。所谓的任务对象其本质就是一个Future类的子类。它会保存运行后的状态,用于获取该协程执行的结果。

 

介绍一下常用的方法:

  • event_loop:事件循环。开启一个事件循环,只需要将函数注册到事件循环,在条件满足的时候调用

  • coroutione:协程对象,使用关键字async声明的函数不会立即执行,而是返回一个协程对象。协程对象就是原生可以挂起的函数

  • task:任务对象。将协程对象进一步封装,就变成了任务,它包含各种任务的状态

  • future:任务结果。不管是将来执行还是没有执行的任务,它都代表这个任务的结果。和task并没有本质上的区别

  • async/await:关键字。前者用于定义一个协程,后者用于挂起阻塞的异步调用

复制代码
import asyncio,time
async def say(name):
    print(name,'hello','开始')
    await asyncio.sleep(2)
    print(name,'hello','结束')

now=lambda:time.time()
start=now()
if __name__ == '__main__':
    #创建协程对象
    result=say('jack')
    #创建事件循环
    loop=asyncio.get_event_loop()
    #创建任务对象,生成任务包
    task=loop.create_task(result)
    print('task:',task)
    #注册协程对象到事件循环并执行
    loop.run_until_complete(task)
    print('task:', task)
    print('耗时:%0.2f' % (now() - start),'s')
复制代码

 

 

 

可以看到,在get_event_loop之后,在加入事件循环之前处于pending状态,在run_until_complete之后,其状态变成了finished

上边的代码task还可以通过asyncio.ensure_future(coroutine)来创建,run_until_complete参数就是future对象,在传入协程之后封装成task,而task是future的子类,可以使用inistance函数检验

创建协程对象如果用gather的话,后边await的返回值就是协程对象的执行结果:

修改下代码即可:

result2=loop.run_until_complete(asyncio.gather(task))
print('result2:',result2)


 获取执行结果

获取协程对象的执行结果有两种方法,一种是通过回调获取,一种是直接result。

    绑定回调

 在task执行完毕后可以获取结果,回调的最后一个参数为future对象,可以通过这个对象来获取协程的返回值,这也就是协程里面常说的绑定回调

 

复制代码
import asyncio,time
async def say(name):
print(name,'hello','开始')
await asyncio.sleep(2)
print(name,'hello','结束')
return '%s 已执行完毕' % name
def callback(future):
print('callback:', future.result())

now=lambda:time.time()
start=now()
if __name__ == '__main__':
#创建协程对象
result=say('jack')
#创建事件循环
loop=asyncio.get_event_loop()
#创建任务对象,生成任务包
task=loop.create_task(result)
# 回调函数
task.add_done_callback(callback)
#注册协程对象到事件循环并执行
loop.run_until_complete(task)
print(task)
print('耗时:%0.2f' % (now() - start),'s')
复制代码

 

 

 

但是如果回调需要多个参数的话怎么办?学过python基础的都知道,偏函数正好能解决该类问题。将future作为固定参数,极大的减少了编程成本,也非常好的遵循了DRY原则。

假设上述代码中的callback函数需要再传入一个时间参数,就可以这么做

复制代码
from functools import partial
import asyncio,time
async def say(name):
    print(name,'hello','开始')
    await asyncio.sleep(2)
    print(name,'hello','结束')
    return '%s 已执行完毕' % name
def callback(now,future):
    print('callback:%s,当前时间:%s'% (future.result(),now))

now=lambda:time.time()
start=now()
if __name__ == '__main__':
    #创建协程对象
    result=say('jack')
    #创建事件循环
    loop=asyncio.get_event_loop()
    #创建任务对象,生成任务包
    task=loop.create_task(result)
    # 回调函数
    task.add_done_callback(partial(callback,time.ctime()))
    #注册协程对象到事件循环并执行
    loop.run_until_complete(task)
    print('耗时:%0.2f' % (now() - start),'s')
复制代码

  直接获取

  将task调用result方法即可

  task.result()

posted @   瘦阿瘦  阅读(259)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
点击右上角即可分享
微信分享提示