MST
星途 面试题库

面试题:Python异步编程的性能优化

在一个包含大量I/O操作的Python异步程序中,如何使用`asyncio`库的`Semaphore`(信号量)来控制并发数量,以避免资源耗尽并提升整体性能?请给出具体代码示例并解释每一步的作用。
26.7万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试
import asyncio


async def io_bound_task(semaphore, task_number):
    async with semaphore:
        print(f"Task {task_number} is starting I/O operation.")
        await asyncio.sleep(1)  # 模拟I/O操作,如网络请求或文件读取
        print(f"Task {task_number} has finished I/O operation.")


async def main():
    semaphore = asyncio.Semaphore(5)  # 创建一个信号量,最多允许5个任务同时运行
    tasks = [io_bound_task(semaphore, i) for i in range(10)]  # 创建10个任务
    await asyncio.gather(*tasks)  # 等待所有任务完成


if __name__ == "__main__":
    asyncio.run(main())

代码解释

  1. 定义 io_bound_task 函数
    • semaphore:传入的信号量对象,用于控制并发。
    • task_number:任务编号,用于标识不同任务。
    • async with semaphore:使用 async with 语句获取信号量。如果当前已有5个任务持有信号量(因为信号量初始值为5),则新任务会在此处等待,直到有任务释放信号量。一旦获取到信号量,任务可以继续执行。
    • await asyncio.sleep(1):模拟I/O操作,如网络请求或文件读取,使当前任务暂停1秒。
    • print 语句:在任务开始和结束I/O操作时打印信息,方便观察任务执行情况。
  2. 定义 main 函数
    • semaphore = asyncio.Semaphore(5):创建一个 Semaphore 对象,其初始值为5,表示最多允许5个任务同时运行。
    • tasks = [io_bound_task(semaphore, i) for i in range(10)]:使用列表推导式创建10个 io_bound_task 任务。
    • await asyncio.gather(*tasks):等待所有任务完成。asyncio.gather 会并发运行传入的所有任务,而信号量则控制同时运行的任务数量。
  3. if __name__ == "__main__" 部分
    • asyncio.run(main()):在Python 3.7+ 中,这是运行异步程序的标准方式,启动 main 函数的执行。通过这种方式,使用 Semaphore 来有效控制包含大量I/O操作的异步程序的并发数量,避免资源耗尽并提升整体性能。