文章目录
- 1. 同步与异步函数的对比
- 1.1 同步函数
- 1.2 异步函数
- 1.3 对比
- 2. 管理多个协程与异常处理
- 2.1 并发执行多个协程
- 2.2 错误处理
- 2.3 任务取消
本文将探索Python中同步与异步编程的基本概念及其区别。还会详细介绍如何使用asyncio库来有效管理协程,包括任务的创建、错误处理和取消等功能。
1. 同步与异步函数的对比
1.1 同步函数
在同步模式下,如果some_function()
进行耗时的I/O操作,比如网络请求或文件读取,程序将在此函数执行期间停止执行,直到操作完成。
def fetch_data():data = some_sync_function() # 耗时操作return data# 同步调用
data = fetch_data()
这种模式下,程序完全阻塞直到some_sync_function()
执行完成。
1.2 异步函数
使用async
和await
创建的异步函数可以在执行中暂停并继续执行,无需阻塞程序:
async def fetch_data():data = await some_async_function() # 异步操作return data
在这种模式下,await
关键字使得fetch_data
在some_async_function()
执行期间暂停,将控制权交还给事件循环,允许执行其他操作。
1.3 对比
特性 | 同步编程 | 异步编程 |
---|---|---|
执行方式 | 阻塞式执行 | 非阻塞式执行 |
资源利用 | 效率较低,CPU等待I/O | 高效,CPU可以处理其他任务 |
复杂性 | 相对简单 | 较复杂,需要理解事件循环 |
适用场景 | 简单脚本、小工具 | I/O密集型应用,如Web服务器 |
控制流 | 线性,易于理解 | 需要使用回调、promises等 |
库/框架 | 无特殊需求 | 需要支持异步的库(如asyncio ) |
性能 | 受限于I/O等待时间 | 可大幅提高响应速度和吞吐率 |
错误处理 | 直接处理 | 需要特殊机制处理异常 |
同步和异步的对比图
2. 管理多个协程与异常处理
在使用asyncio
进行并发编程时,不仅需要管理多个协程的并发执行,同时也需要妥善处理可能出现的错误和取消正在运行的任务。
2.1 并发执行多个协程
asyncio.gather
是一个非常实用的函数,它允许同时启动多个协程,并等待所有协程执行完成。这样可以有效地利用时间,因为它允许多个协程并行执行而非顺序执行。
import asyncioasync def count():print("One", end=' ') # 确保在打印后不自动换行await asyncio.sleep(1)print("Two", end=' ') # 同样不换行async def main():await asyncio.gather(count(), count(), count())asyncio.run(main())
# 输出:One One One Two Two Two
count
协程会先打印“One”,然后等待1秒,接着打印“Two”。由于使用了asyncio.gather
,三个count
协程会并行执行,因此总的等待时间仅为1秒,而不是三次各自等待1秒。
加餐:end是干嘛用的
默认情况下,print
函数会在每次调用后添加一个换行符,但如果设置end
参数为一个空字符串''
,那么输出将不会在末尾添加换行符。
2.2 错误处理
在asyncio
中处理错误是确保程序健壮性和响应性的关键。错误处理通常通过使用try-except
块来实现,这允许程序在遇到预期内的异常时优雅地恢复。
import asyncioasync def error_task():raise ValueError("Something went wrong!")async def main():task = asyncio.create_task(error_task())try:await taskexcept ValueError as e:print(f"Caught an error: {e}")asyncio.run(main())
# 输出:Caught an error: Something went wrong!
在这个例子中,error_task
协程故意抛出一个ValueError
异常。在main
函数中,使用try-except
块来捕获并处理这个异常。这样的错误处理机制确保了即使在异步任务失败时,程序也能继续运行,从而提高了整体的容错性。
asyncio.create_task
简介
asyncio.create_task()
函数用于并行运行协程。此函数将协程封装成一个Task
对象,并安排其在事件循环中执行。
2.3 任务取消
在asyncio
中,取消任务是异步编程中的另一个重要方面,它允许开发者在任务不再需要时终止执行,从而释放资源。
import asyncioasync def cancellable_task():try:print("Task starts")await asyncio.sleep(10) # 假设这是一个长时间运行的任务print("Task completed")except asyncio.CancelledError:print("Task was cancelled!")async def main():task = asyncio.create_task(cancellable_task())await asyncio.sleep(1) # 给任务一点时间开始执行task.cancel() # 取消任务try:await taskexcept asyncio.CancelledError:print("Caught cancellation in main")asyncio.run(main())
# 输出:
# Task starts
# Task was cancelled!
# Caught cancellation in main
在这个例子中,cancellable_task
开始执行后,通过调用task.cancel()
来请求取消任务。任务中的asyncio.sleep
调用会在收到取消请求时抛出一个asyncio.CancelledError
。在任务的try-except
块中捕获这个异常,可以执行任何必要的清理工作。在main
函数中,等待任务完成,并处理可能由任务取消引发的异常。
参考:Synchronous vs Asynchronous Programming: Models, Differences, Use Cases
推荐: python 错误记录