约 2921 字
约 15 分钟
异步 I/O(Asynchronous Input/Output) 是一种 不阻塞程序执行 的 I/O 操作方式。发起 I/O 操作后,不必等待操作完成,程序可以继续做其他事情;当操作完成时,通过回调、事件循环或协程机制通知程序处理结果。
Python 的异步 I/O 基于协程实现。使用async
关键字来创建一个异步函数,对异步函数的调用不会执行该函数,而是生成一个协程对象。
对每一个协程对象,都必须等待其结束(即使是没有启动的协程),否则会产生一个 RuntimeWarning
类型的异常。
示例 :
# 创建一个异步函数
async def say_hello():
print("hello world")
# 创建协程
coro = say_hello()
print("协程对象", coro)
Loading...
要启动一个协程,有三种方式:
asyncio.run
运行一个协程对象 await
关键字,这种方法只能在另一个 async
函数中才能使用 asyncio.create_task
await
必须在async
函数中才能使用,因此无法启动协程的顶层入口点,此时只能使用asyncio.run
函数。
await
让出当前协程并运行目标协程,当前协程直到目标目标的状态变为done
时才会恢复就绪。 如果await
的目标不是一个协程(例如Task和Future),让出当前协程后,事件循环(EventLoop
)会从就绪队列中选择一个协程运行。
asyncio.create_task
让出当前协程并运行目标协程,当前协程不会等待而是加入就绪队列。
只要目标协程让出,当前协程就有机会执行,从而将启动多个协程,实现并发执行。
返回的Task
对象也可以在适当的时候使用await
等待其结束。
协程的状态转移:
awai
示例:
import asyncio
import time
async def say_hello():
print("hello", time.strftime('%X'))
await asyncio.sleep(1)
print("hello", time.strftime('%X'))
async def say_world():
print("world", time.strftime('%X'))
await asyncio.sleep(1)
print("world", time.strftime('%X'))
# 顶层入口点
async def main():
await say_hello() # 启动say_hello()返回的协程,并等待其结束
await say_world() # 要等到前一个await结束后,才会启动
# 启动顶层入口点
asyncio.run(main())
运行结果 :
hello 15:27:26 hello 15:27:27 world 15:27:27 world 15:27:28
asyncio.create_task
示例 :
import asyncio
import time
async def say_hello():
print("hello", time.strftime('%X'))
await asyncio.sleep(1)
print("hello", time.strftime('%X'))
async def say_world():
print("world", time.strftime('%X'))
await asyncio.sleep(1)
print("world", time.strftime('%X'))
# 顶层入口点
async def main():
task_say_hello = asyncio.create_task(say_hello()) # 启动协程不等待
task_say_world = asyncio.create_task(say_world())
await task_say_hello
await task_say_world
# 启动顶层入口点
asyncio.run(main())
运行结果 :
hello 15:29:41 world 15:29:41 hello 15:29:42 world 15:29:42
通过上面两个示例打印的顺序和时间可以看出 await
和 asyncio.create_task
的区别:
await
启动另一个协程时,使当前协程进入等待状态,需要启动的协程运行完毕,当前协程才能恢复就绪,因此运行流程是串行的 asyncio.create_task
启动另一个协程时,当前协程仍然是就绪状态,因此运行流程是并发的。 创建于 2025/5/8 18:44:18
更新于 2025/5/8 18:51:26