
Python使用
async/await
async def
await
在Python中,
async/await
async def
await
async def
await
await
一个最基本的例子可能长这样:
import asyncio
async def say_hello(delay, message):
print(f"[{asyncio.current_task().get_name()}] 开始等待 {delay} 秒...")
await asyncio.sleep(delay) # 这是一个异步的非阻塞等待
print(f"[{asyncio.current_task().get_name()}] {message}!")
async def main():
# 创建并运行两个协程任务
task1 = asyncio.create_task(say_hello(3, "Hello from Task 1"), name="Task-1")
task2 = asyncio.create_task(say_hello(1, "Hi from Task 2"), name="Task-2")
# 等待这两个任务完成
await task1
await task2
print("所有任务都完成了。")
if __name__ == "__main__":
asyncio.run(main())在这个例子里,
say_hello
main
say_hello
await
asyncio.sleep
Task-1
Task-2
立即学习“Python免费学习笔记(深入)”;
在我看来,Python异步编程最核心的优势在于它能够以极低的资源开销实现高并发,尤其是在I/O密集型任务中。我们都知道,CPU的速度远超硬盘读写或网络传输。在传统的同步编程模式下,当程序发起一个网络请求或文件读取时,它会傻傻地等待,直到操作完成才能继续执行。这段等待时间,CPU其实是闲置的,什么也没做。这就像你点了一份外卖,然后就坐在门口,什么也不干,直到外卖送到。
异步编程改变了这种模式。它允许程序在等待I/O操作时“暂停”当前任务,将CPU的控制权交还给一个调度器(也就是事件循环),让调度器去运行其他已经准备好的任务。当I/O操作完成后,调度器会通知之前暂停的任务继续执行。这就像你点完外卖后,可以去洗个澡、看会儿电视,甚至再点一份水果,等外卖快到了再准备开门。这样,你的时间就得到了更有效的利用。
与传统同步编程模式的主要区别:
async/await
我个人的体会是,很多人初次接触异步编程会觉得它很“魔幻”,甚至有点反直觉。但一旦你理解了它不是为了让CPU计算得更快,而是为了让CPU在等待外部资源时也能保持“忙碌”,去做一些有意义的事情,那么它的价值就显而易见了。它不是万能药,计算密集型任务依然需要多进程来利用多核CPU,但对于网络服务、爬虫、数据处理管道等I/O密集型应用,异步编程无疑是提升性能和响应速度的利器。
asyncio
启动和管理
asyncio
asyncio
1. 使用asyncio.run()
这是目前最简洁、最推荐的启动事件循环的方式。
asyncio.run()
import asyncio
async def main_coroutine():
print("主协程开始")
await asyncio.sleep(1)
print("主协程结束")
if __name__ == "__main__":
print("启动事件循环...")
asyncio.run(main_coroutine())
print("事件循环已关闭。")asyncio.run()
对于大多数简单的脚本或应用程序,
asyncio.run()
2. 手动管理事件循环 (适用于特定场景或旧代码)
在Python 3.7之前,或者当你需要在更复杂的环境中(例如,在现有线程中集成
asyncio
import asyncio
async def my_task(name):
print(f"任务 {name} 开始")
await asyncio.sleep(2)
print(f"任务 {name} 结束")
def manual_loop_management():
loop = asyncio.get_event_loop() # 获取当前线程的事件循环,如果没有则创建
try:
print("手动管理:运行任务 A")
loop.run_until_complete(my_task("A")) # 运行一个协程直到完成
print("手动管理:运行多个任务")
task_b = loop.create_task(my_task("B")) # 创建一个任务
task_c = loop.create_task(my_task("C"))
loop.run_until_complete(asyncio.gather(task_b, task_c)) # 等待多个任务完成
finally:
loop.close() # 确保事件循环被关闭
if __name__ == "__main__":
# asyncio.run(main_coroutine()) # 使用推荐方式
manual_loop_management() # 使用手动方式手动管理涉及以下步骤:
asyncio.get_event_loop()
loop.run_until_complete(coroutine)
loop.close()
3. 有效地管理并发任务:asyncio.create_task()
asyncio.gather()
仅仅启动事件循环是不够的,你还需要有效地管理多个并发执行的协程。
asyncio.create_task(coroutine)
await
Task
create_task
await
async def fetch_data(url):
print(f"正在从 {url} 获取数据...")
await asyncio.sleep(2) # 模拟网络延迟
print(f"从 {url} 获取数据完成。")
return f"Data from {url}"
async def main_tasks():
task1 = asyncio.create_task(fetch_data("http://example.com/api/1"))
task2 = asyncio.create_task(fetch_data("http://example.com/api/2"))
# 此时 task1 和 task2 已经开始在后台运行了
print("任务已创建,正在等待结果...")
result1 = await task1 # 等待 task1 完成
result2 = await task2 # 等待 task2 完成
print(f"收到结果: {result1}, {result2}")
# asyncio.run(main_tasks())*`asyncio.gather(coros_or_futures, loop=None, return_exceptions=False)`:** 这是一个非常实用的工具,用于同时运行并等待多个可等待对象(协程或Future)完成。它会收集所有结果,并按传入顺序返回。
async def main_gather():
results = await asyncio.gather(
fetch_data("http://example.com/api/3"),
fetch_data("http://example.com/api/4"),
fetch_data("http://example.com/api/5")
)
print(f"所有数据都已获取: {results}")
# asyncio.run(main_gather())asyncio.gather()
我的经验告诉我,事件循环是
asyncio
create_task
gather
async/await
在实际的异步编程中,仅仅启动和等待任务是不够的,我们还需要妥善处理可能出现的异常和任务取消。这就像在现实世界中,计划总赶不上变化,我们需要有应对突发状况的机制。
1. 异常处理
异步任务中的异常处理与同步代码类似,主要通过
try...except
捕获单个协程的异常: 你可以在
await
try...except
import asyncio
async def might_fail_task(task_id):
if task_id % 2 != 0:
raise ValueError(f"任务 {task_id} 故意失败了!")
await asyncio.sleep(1)
return f"任务 {task_id} 成功完成。"
async def handle_single_task_error():
try:
result = await might_fail_task(1) # 这个会失败
print(result)
except ValueError as e:
print(f"捕获到异常: {e}")
try:
result = await might_fail_task(2) # 这个会成功
print(result)
except ValueError as e:
print(f"捕获到异常: {e}") # 不会执行
# asyncio.run(handle_single_task_error())asyncio.gather()
asyncio.gather()
gather
async def handle_gather_error_default():
try:
results = await asyncio.gather(
might_fail_task(1), # 会失败
might_fail_task(2), # 会成功,但可能被取消
might_fail_task(3) # 会失败,但可能在第一个异常抛出前被取消
)
print(f"所有任务完成: {results}")
except ValueError as e:
print(f"asyncio.gather 捕获到异常: {e}")
# 此时,其他任务可能已经被取消了
# asyncio.run(handle_gather_error_default())asyncio.gather()
return_exceptions=True
gather
return_exceptions=True
async def handle_gather_error_return_exceptions():
results = await asyncio.gather(
might_fail_task(1), # 失败
might_fail_task(2), # 成功
might_fail_task(3), # 失败
return_exceptions=True # 关键参数
)
print("所有任务都处理完毕(包括失败的):")
for i, res in enumerate(results):
if isinstance(res, Exception):
print(f" 任务 {i+1} 失败: {res}")
else:
print(f" 任务 {i+1} 成功: {res}")
# asyncio.run(handle_gather_error_return_exceptions())这种方式在处理多个独立且不互相依赖的任务时非常有用,比如批量处理数据,你希望即使某些数据处理失败,也不影响其他数据的处理。
2. 任务取消
在异步编程中,任务取消是一个重要的概念。你可能需要停止一个长时间运行的任务,例如用户关闭了一个页面,或者一个操作超时了。
task.cancel()
Task
cancel()
await
asyncio.CancelledError
async def long_running_task(task_name):
print(f"[{task_name}] 任务开始...")
try:
for i in range(5):
print(f"[{task_name}] 工作中... {i+1}/5")
await asyncio.sleep(1) # 这是一个可能的取消点
except asyncio.CancelledError:
print(f"[{task_name}] 任务被取消了!执行清理工作...")
finally:
print(f"[{task_name}] 任务结束(无论成功或取消)。")
async def main_cancel():
task = asyncio.create_task(long_running_task("A"))
await asyncio.sleep(2.5) # 等待任务运行一段时间
print("主程序:请求取消任务 A...")
task.cancel() # 发送取消请求
try:
await task # 等待以上就是Python怎么使用async/await_Python异步编程async/await入门的详细内容,更多请关注php中文网其它相关文章!
编程怎么学习?编程怎么入门?编程在哪学?编程怎么学才快?不用担心,这里为大家提供了编程速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号