定义异步函数

import asyncio


async def hello(name: str):
    await asyncio.sleep(2)
    return f"Hello, {name}!"

导入asyncio包;
通过 async def 定义异步函数。

手动创建任务

import asyncio


async def hello(name: str):
    await asyncio.sleep(2)
    return f"Hello, {name}!"


async def main():
    # 创建三个任务
    task1 = asyncio.create_task(hello("Alice"))
    task2 = asyncio.create_task(hello("Bob"))
    task3 = asyncio.create_task(hello("Charlie"))
    # 等待三个任务完成
    Alice_result = await task1
    Bob_result = await task2
    Charlie_result = await task3
    # 打印结果
    print(Alice_result, Bob_result, Charlie_result)


if __name__ == "__main__":
    # 运行异步程序
    asyncio.run(main())

通过asyncio.create_task()创建的任务返回是一个可执行函数,需要使用await获得返回的值。

自动创建任务

使用asyncio.gather()创建自动任务
import asyncio


async def hello(name: str):
    await asyncio.sleep(2)
    return f"Hello, {name}!"


async def main():
    # 创建三个任务
    results = await asyncio.gather(hello("Alice"), hello("Bob"), hello("Charlie"))
    print(results)


if __name__ == "__main__":
    # 运行异步程序
    asyncio.run(main())

使用asyncio.as_completed()创建自动任务

import asyncio


async def hello(name: str):
    await asyncio.sleep(2)
    return f"Hello, {name}!"


async def main():
    # 创建三个任务
    results = asyncio.as_completed([hello("Alice"), hello("Bob"), hello("Charlie")])
    for result in results:
        print(await result)


if __name__ == "__main__":
    # 运行异步程序
    asyncio.run(main())

asyncio.gather 与 asyncio.as_completed 的区别

1. asyncio.gather

  • 作用:并发运行多个协程,并一次性收集所有结果。

  • 特点

    • 按传入顺序返回结果(即使某些任务先完成,也不会提前返回)。
    • 如果有一个任务报错,gather 会立刻抛异常,默认会取消其它未完成任务(可通过参数 return_exceptions=True 来改变)。
  • 适用场景
    当你需要 一次性得到所有结果,比如并发请求多个 API,最后要拼装数据。

  1. asyncio.as_completed

  • 作用:返回一个迭代器,谁先完成就先产出结果。

  • 特点

    • 结果顺序取决于完成的先后
    • 更适合 流式处理:一个任务完成了就立刻消费它的结果,而不是等所有任务结束。
  • 适用场景
    当你想 边跑边处理,比如爬虫中哪个网页先返回就先处理,提升吞吐效率。

    核心区别总结

    特性 asyncio.gather asyncio.as_completed
    返回结果顺序 按传入任务顺序 按任务完成顺序
    返回方式 一次性返回所有结果 一个个产出结果
    错误处理 默认立即抛出并取消其它任务 某个任务报错时只影响它本身
    适用场景 需要所有结果统一处理 需要流式处理、谁先来先处理

await 的作用

暂停当前协程,等待一个“可等待对象”的结果返回,然后继续往下执行

1. 可等待对象(awaitable)

能被 await 的对象必须是 awaitable,常见有三类:

  1. 协程对象(由 async def 函数调用返回的对象)
  2. Task 对象asyncio.create_task() 返回的任务)
  3. Future 对象(底层异步结果容器)

2. 工作原理

当执行到 await expr

  1. expr 必须是一个 awaitable。
  2. 当前协程会 挂起(yield control),把执行权交给事件循环。
  3. 事件循环可以在此期间去运行别的任务,提高并发效率。
  4. expr 对象完成(返回值或异常),事件循环会恢复该协程,并把结果赋给 await 表达式。

3. 直观类比
  • await ≈ 同步代码里的 result = func(),但不会阻塞整个线程,只是 挂起当前协程

  • 好比在餐厅点菜:

    • await 就是“我点了菜,等它做好再吃”。

    • 服务员(事件循环)可以在你等菜时去服务别的客人(运行其它协程)。

将普通函数变为异步函数

使用asyncio.to_thread()将普通函数创建为异步任务

会把一个同步阻塞函数丢到一个线程池里执行,并返回一个可 await 的结果。

也就是说:

  • async 环境里,有些第三方库或者函数(比如 time.sleep()、文件 I/O、CPU 计算)是同步阻塞的,直接调用会卡住事件循环,影响并发。
  • asyncio.to_thread 包装后,就能把它放进后台线程运行,不会阻塞事件循环。
import asyncio
import time


def hello(name: str):
    time.sleep(2)
    return f"Hello, {name}!"


async def main():
    # 创建三个任务
    results = asyncio.as_completed([asyncio.to_thread(hello, "Alice!"),
                                    asyncio.to_thread(hello, "Bob!"),
                                    asyncio.to_thread(hello, "Charlie!")])
    for result in results:
        print(await result)


if __name__ == "__main__":
    # 运行异步程序
    start = time.time()
    asyncio.run(main())
    end = time.time()-start
    print(f"Time taken: {end:.2f} seconds")