Python 标准库 asyncio

  1. 概念
    1. Event Loop(事件循环)
    2. Coroutine(协程)
    3. Task(任务)
  2. 基本用法
    1. await
    2. asyncio.create_task()
    3. asyncio.gather()
    4. asyncio.TaskGroup
  3. 参考

概念

按照 Python 文档的定义:

asyncio 是用来编写并发代码的库,使用 async / await 语法。

它适合网络请求、流式连接、子进程等需要等待 I/O 的任务。asyncio 提供异步文件描述符接口,但普通磁盘文件读写仍可能阻塞事件循环,通常要交给线程或专用异步库。

理解 asyncio 需要区分协程、Task 和事件循环:协程可以被 await 直接驱动,也可以被包装成 Task 后由事件循环并发调度。Task 不是协程执行的前置条件,而是并发调度协程的一种方式。

Event Loop(事件循环)

Event loop 是 asyncio 的调度中心,负责运行就绪的 Task、处理 I/O 事件,并在等待条件满足后恢复任务。

asyncio.run(main()) 会创建事件循环,把顶层协程运行至完成,然后关闭事件循环。

Coroutine(协程)

  • 协程函数(coroutine function)

    使用 async def 定义协程函数。

    比如编写一个普通函数print_hello()

    def print_hello():
        print("Hello")
    

    调用print_hello()函数输出为Hello

    当把def改成async def

    async def print_hello():
        print("Hello")
    

    此时 print_hello 是协程函数。

  • 协程对象(coroutine object)

    调用协程函数会返回协程对象,但不会立即执行函数体。

    async def print_hello():
        print("Hello")
        
    print(print_hello())
    

    输出结果为<coroutine object print_hello at 0x7fdb21345b40>

    直接调用协程函数不会执行里面的代码(输出 Hello),只会返回一个协程对象。

Task(任务)

Task 是对协程的调度包装。asyncio.create_task(coro()) 会把协程安排到当前事件循环中运行,并立即返回 Task 对象;当前协程可以继续做其他工作,再在需要结果时 await task


基本用法

await

最小的顺序执行例子:

import asyncio

async def main():
    print('Hello ...')
    await asyncio.sleep(1)
    print('... World!')

asyncio.run(main())

把两个协程依次 await

import asyncio
from datetime import datetime


async def print_hello():
    await asyncio.sleep(1)
    print('Hello ...')


async def print_world():
    await asyncio.sleep(1)
    print('... World!')


async def main():
    print(datetime.now().strftime("%H:%M:%S"))
    await print_hello()
    await print_world()
    print(datetime.now().strftime("%H:%M:%S"))


asyncio.run(main())

执行后输出为

22:13:22
Hello …
… World!
22:13:24

总耗时约 2 秒,因为 print_world() 要等 print_hello() 完成后才开始。这里的 await coroutine 不会自动创建一个独立 Task;它会暂停当前协程,直接驱动被等待的协程,直到获得结果。要让两个操作重叠执行,需要显式创建 Task,或使用 gather() / TaskGroup

传给 asyncio.run()main() 是协程对象。它是程序的顶层入口,asyncio.run() 负责把它运行至完成。

asyncio.create_task()

asyncio.create_task() 会立即把协程包装成 Task 并交给当前事件循环调度。创建 Task 后,当前协程可以继续执行其他代码,直到显式 await 该 Task 获取结果。

import asyncio


async def worker(name, delay):
    await asyncio.sleep(delay)
    return f"{name} finished"


async def main():
    task = asyncio.create_task(worker("task-a", 1))
    print("task created")

    result = await task
    print(result)


asyncio.run(main())

不要创建 Task 后直接退出事件循环,否则尚未完成的任务会被取消。需要结果或需要确保任务执行完成时,应保存 Task 引用并等待它。

asyncio.gather()

asyncio.gather() 可以同时等待多个可等待对象。这里两个任务会并发执行,总耗时接近较慢任务的 2 秒,而不是两者相加的 3 秒。

import asyncio


async def worker(name, delay):
    await asyncio.sleep(delay)
    return f"{name} finished"


async def main():
    results = await asyncio.gather(
        worker("task-a", 2),
        worker("task-b", 1),
    )
    print(results)


asyncio.run(main())

返回结果的顺序与传入顺序一致,而不是按任务完成顺序排列。默认情况下,任务抛出的异常会向调用方传播;需要把异常作为结果收集时,可以使用 return_exceptions=True,但随后必须逐项检查结果。

asyncio.TaskGroup

Python 3.11 及以上可使用 TaskGroup 管理一组相关任务。退出上下文时会等待所有任务;任一任务失败时,其余任务会被取消,因此比手工维护多个 Task 更适合结构化并发。

import asyncio


async def worker(name, delay):
    await asyncio.sleep(delay)
    return f"{name} finished"


async def main():
    async with asyncio.TaskGroup() as group:
        task_a = group.create_task(worker("task-a", 2))
        task_b = group.create_task(worker("task-b", 1))

    print(task_a.result(), task_b.result())


asyncio.run(main())

参考

asyncio的概念概述
asyncio — 异步 I/O
协程与任务


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。

文章标题:Python 标准库 asyncio

字数:1.1k

本文作者:

发布时间:2025-12-14, 14:39:00

最后更新:2026-08-26, 21:18:00

原始链接:https://cnlnn.pages.dev/posts/python-library-asynico/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。