在 Python 3.8 以后的版本中,异步编程变得越来越重要。本文将系统介绍 Python 标准库中的异步编程工具,带领大家掌握 async
/await
语法和 asyncio
的使用。
从一个简单的场景开始
假设我们在处理一些耗时的 I/O 操作,比如读取多个文件或处理多个数据。为了模拟这种场景,我们先用 time.sleep()
来代表耗时操作:
import time
import random
def process_item(item):
# 模拟耗时操作
print(f"处理中:{
item}")
process_time = random.uniform(0.5, 2.0)
time.sleep(process_time)
return f"处理完成:{
item},耗时 {
process_time:.2f} 秒"
def process_all_items():
items = ["任务A", "任务B", "任务C", "任务D"]
results = []
for item in items:
result = process_item(item)
results.append(result)
return results
if __name__ == "__main__":
start = time.time()
results = process_all_items()
end = time.time()
print("\n".join(results))
print(f"总耗时:{
end - start:.2f} 秒")
处理中:任务A
处理中:任务B
处理中:任务C
处理中:任务D
处理完成:任务A,耗时 1.97 秒
处理完成:任务B,耗时 1.28 秒
处理完成:任务C,耗时 0.66 秒
处理完成:任务D,耗时 1.80 秒
总耗时:5.72 秒
这段代码的问题很明显:每个任务都必须等待前一个任务完成才能开始。如果有4个任务,每个任务平均耗时1秒,那么总耗时就接近4秒。
认识 async/await
Python 引入了 async
/await
语法来支持异步编程。当我们在函数定义前加上 async
关键字时,这个函数就变成了一个"协程"(coroutine)。而 await
关键字则用于等待一个协程完成。让我们改写上面的代码:
import asyncio
import random
import time
async def process_item(item):
print(f"处理中:{
item}")
# async 定义的函数变成了协程
process_time = random.uniform(0.5, 2.0)
# time.sleep() 换成 asyncio.sleep()
await asyncio.sleep(process_time) # await 等待异步操作完成
return f"处理完成:{
item},耗时 {
process_time:.2f} 秒"
async def process_all_items():
items = ["任务A", "任务B", "任务C", "任务D"]
# 创建任务列表
tasks = [
asyncio.create_task(process_item(item))
for item in items
]
print("开始处理")
results = await asyncio.gather(*tasks)
return results
async def main():
start = time