【python】asyncio异步编程

1. 协程

协程(Coroutine)是计算机程序组件,它允许执行的暂停和恢复,通常用于并发编程。协程可以在执行过程中挂起,等待外部事件,然后在事件完成后恢复执行,而不像线程那样需要操作系统进行上下文切换。协程的这种特性使得它在处理 I/O 密集型任务(例如,网络请求、文件读写等操作)时非常高效,因为它避免了线程切换的开销。协程没有用户态内核态之间的切换。

在 Python 中,协程是通过async def关键字定义的函数。协程函数内部可以使用await关键字来挂起当前协程的执行,等待另一个协程或异步操作完成。

协程的主要特点

  • 挂起和恢复:协程可以在执行过程中暂停,等待外部事件(如 I/O 操作),然后在事件完成后恢复执行。
  • 高效:由于协程的挂起和恢复是在用户空间进行的,不需要操作系统的上下文切换,因此比线程更高效。
  • 协作式多任务:协程通过协作来实现多任务,即一个协程在挂起之前会确保其他协程有机会执行。
    协程的基本使用

2. asyncio

asyncio.run

import asyncio

async def task1():
    print("Task 1 started")
    await asyncio.sleep(2)  # 模拟耗时操作
    print("Task 1 finished")

async def task2():
    print("Task 2 started")
    await asyncio.sleep(1)  # 模拟耗时操作
    print("Task 2 finished")

async def task3():
    print("Task 3 started")
    await asyncio.sleep(3)  # 模拟耗时操作
    print("Task 3 finished")

async def main():
    # 创建任务
    # 创建task对象,将当前任务添加到事件循环
    task_1 = asyncio.create_task(task1())
    task_2 = asyncio.create_task(task2())
    task_3 = asyncio.create_task(task3())

    # 等待所有任务完成
    await asyncio.gather(task_1, task_2, task_3)
    # 也可以用await asyncio.wait实现
    # done, pending = await asyncio.wait([task1, task2, task3])

# 运行事件循环
asyncio.run(main())

代码解释

  1. 定义三个协程:

    • task1、task2 和 task3 分别代表三个并发任务。
    • 每个任务内部使用 await asyncio.sleep(n) 来模拟耗时操作,n 表示耗时的秒数。
  2. 定义主协程 main:

    • 使用 asyncio.create_task 将每个任务包装成一个任务对象。
    • 使用 asyncio.gather 并发执行所有任务,并等待它们完成。
  3. 运行事件循环:

    • 使用asyncio.run(main())运行主协程,启动事件循环并执行所有任务。

运行结果
运行上述代码后,你会看到类似如下的输出:

Task 1 started
Task 2 started
Task 3 started
Task 2 finished
Task 1 finished
Task 3 finished

asyncio.get_event_loop

import asyncio

async def task1():
    print("Task 1 started")
    await asyncio.sleep(2)  # 模拟耗时操作
    print("Task 1 finished")

async def task2():
    print("Task 2 started")
    await asyncio.sleep(1)  # 模拟耗时操作
    print("Task 2 finished")

async def task3():
    print("Task 3 started")
    await asyncio.sleep(3)  # 模拟耗时操作
    print("Task 3 finished")

def main():
    loop = asyncio.get_event_loop()
    try:
        # 创建任务
        tasks = [
        # 创建task对象,将当前任务添加到事件循环
            loop.create_task(task1()),
            loop.create_task(task2()),
            loop.create_task(task3())
        ]
        # 运行事件循环,直到所有任务完成
        loop.run_until_complete(asyncio.gather(*tasks))
    finally:
        loop.close()

if __name__ == "__main__":
    main()

代码解释

  1. 定义三个协程:

    • task1、task2 和 task3 分别代表三个并发任务。
    • 每个任务内部使用await asyncio.sleep(n)来模拟耗时操作,n 表示耗时的秒数。
  2. 定义主函数 main:

    • 获取事件循环 loop。
    • 使用 loop.create_task 将每个任务包装成一个任务对象,并存储在 tasks 列表中。
    • 使用 loop.run_until_complete(asyncio.gather(*tasks)) 运行事件循环,直到所有任务完成。
    • 在 finally 块中关闭事件循环 loop.close()
  3. 运行主函数:

if __name__ == "__main__" 块中调用 main() 函数。

run和get_event_loop的区别

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(*tasks))

asyncio.run(main())

的效果是一样的,后者是python3.7的实现方式

await asyncio.wait 和asycio.gather的区别

await asyncio.wait()asyncio.gather() 都是用于等待多个协程完成的工具,但它们之间有一些关键区别:

  1. 功能差异

    • asyncio.gather():将多个协程作为参数传入,启动并等待所有协程完成,返回所有协程的结果(以相同顺序)。如果其中任何一个协程抛出异常,gather() 会传播该异常。
    • asyncio.wait():接收一个可迭代的协程(如列表),并根据指定的等待条件(return_when 参数)返回完成的和未完成的任务。它返回的是一个元组,包含完成的和未完成的任务集合。
  2. 返回结果

    • asyncio.gather() 返回协程的结果列表。
    • asyncio.wait() 返回已完成和未完成任务的集合元组 (done, pending)
  3. 异常处理

    • asyncio.gather() 遇到异常时会传播异常并终止执行。
    • asyncio.wait() 默认不会传播异常,而是将异常作为任务的一部分返回,除非你手动处理任务结果。
  4. 使用场景

    • asyncio.gather() 更适合在需要获取所有任务结果的情况下使用。
    • asyncio.wait() 更适合需要更灵活控制任务的场景,比如等待第一个任务完成或检查是否有任务超时等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值