python异步之async与await

Python 异步编程的工作原理如下:

事件监听

  • asyncio 会设置各种事件监听器,比如网络 I/O、文件 I/O、定时器等。
  • 当这些监听的事件发生时,asyncio 会将事件添加到事件队列中。

事件循环

  • asyncio 的核心是一个事件循环,它会定期检查事件队列中是否有新的事件需要处理。
  • 事件循环的检查频率通常由操作系统的调度策略决定,可能是 1ms、10ms 或更长。

事件分发

  • 当事件队列中有新事件时,事件循环会从队列中取出事件,并分发给相应的事件处理函数。
  • 事件处理函数会根据事件的类型和内容执行相应的异步操作。

yielding 切换

  • 在事件处理函数中,如果遇到耗时的操作,可以使用 await 关键字让出 CPU 控制权。
  • 这样事件循环就可以转而处理其他就绪的事件,提高整体的并发性和吞吐量。

资源管理

  • 异步操作完成后,asyncio 会根据需要释放或分配相关的系统资源,比如网络连接、数据库连接等。
  • 资源的管理同样是通过事件循环的定期检查来实现的。

可以看到,Python 异步编程的本质也是基于定期检查事件状态的时间驱动机制。这种机制可以帮助 Python 充分利用 CPU 资源,提高程序的并发性和响应速度,是 Python 异步编程的核心原理。

async

在 Python 中,async 关键字用于声明一个异步函数,它的执行逻辑如下:

函数声明

  • 使用 async def 关键字声明一个异步函数。
  • 异步函数内部可以使用 await 关键字来等待异步操作的完成。

函数调用

  • 调用异步函数时,它会返回一个 coroutine 对象,而不是直接执行函数体内的代码。
  • 这个 coroutine 对象可以被传递给 await 关键字,用于等待异步函数的执行完成。

事件循环

  • 异步函数的执行需要依赖于事件循环(event loop)。
  • 事件循环是一个无限循环,它会检查是否有就绪的异步任务,并依次执行它们。

任务的执行

  • 当一个协程(coroutine)被传递给事件循环时,它会被封装成一个 Task 对象。
  • 事件循环会检查 Task 对象的状态,如果它准备就绪,就会恢复协程的执行。
  • 如果协程中有 await 语句,事件循环会暂停当前协程的执行,转而去执行其他就绪的协程。

错误处理

  • 如果协程内部发生异常,该异常会被传播到调用者,可以使用 try-except 块进行处理。

下面是一个简单的示例,演示了 async 的执行逻辑:


import asyncio

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main():
    print(f"started at {asyncio.get_running_loop().time()}")

    await say_after(1, 'hello')
    await say_after(2, 'world')

    print(f"finished at {asyncio.get_running_loop().time()}")

asyncio.run(main())

在这个例子中:

  • main() 函数是一个异步函数,它调用了两个异步函数 say_after()。
  • 在 main() 函数中,await 关键字用于等待 say_after() 函数的执行完成。
  • 当 main() 函数被传递给事件循环时,它会被封装成一个 Task 对象。
  • 事件循环会检查 Task 对象的状态,如果它准备就绪,就会恢复 main() 函数的执行。
  • 当遇到 await 时,当前协程(main)会暂停执行,事件循环会转而执行其他就绪的协程。
  • 当 say_after() 函数执行完成时,事件循环会恢复 main() 函数的执行,并将结果赋值给被 await 的变量。

await

在 Python 中,await 关键字是用于处理异步操作的,它是 Python 3.5 引入的语法糖。await 被用于等待一个异步函数的执行结果。下面我们来详细了解一下 await 的执行逻辑。

异步函数的调用

  • 当一个异步函数被调用时,它会立即返回一个 coroutine 对象,而不是直接执行函数体内的代码。
  • 这个 coroutine 对象可以被传递给 await 关键字,用于等待异步函数的执行完成。

await 关键字的执行

  • 当遇到 await 关键字时,当前协程会暂停执行,将控制权交给事件循环(event loop)。
  • 事件循环会检查被 await 的对象是否已经准备好(ready)。如果准备好了,就会恢复当前协程的执行,继续执行后续代码。
  • 如果被 await 的对象还没有准备好,事件循环会挂起当前协程,转而去执行其他就绪的协程,直到被 await 的对象准备好。

异步函数的返回值

  • 当一个异步函数执行完成时,它会返回一个 Future 对象,表示异步操作的结果。
  • 在 await 表达式中,这个 Future 对象的结果会被赋值给被 await 的变量。

错误处理

  • 如果被 await 的对象发生异常,该异常会被传播到调用者,可以使用 try-except 块进行处理。

下面是一个简单的示例,演示了 await 的执行逻辑:


import asyncio

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main():
    print(f"started at {asyncio.get_running_loop().time()}")

    await say_after(1, 'hello')
    await say_after(2, 'world')

    print(f"finished at {asyncio.get_running_loop().time()}")

asyncio.run(main())

在这个例子中:

  • main() 函数是一个异步函数,它调用了两个异步函数 say_after()。
  • 在 main() 函数中,await 关键字用于等待 say_after() 函数的执行完成。
  • 当遇到 await 时,当前协程(main)会暂停执行,事件循环会转而执行其他就绪的协程。
  • 当 say_after() 函数执行完成时,事件循环会恢复 main() 函数的执行,并将结果赋值给被 await 的变量。
  • 36
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cherry Xie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值