Skip to content
LlamaIndex 文档版本 跟随上游 源快照 5d3e3c4d 更新于 2026-10-15

如果你是异步编程的新手,这一页就是为你准备的。

具体到 LlamaIndex,很多操作和函数都支持异步执行。这让你可以同时运行多个操作而不阻塞主线程,在很多场景下能显著提升整体吞吐与性能。

以下是你需要理解的几个关键概念:

1. asyncio 基础

  • 事件循环(Event Loop):事件循环负责异步操作的调度与执行。它不断检查并执行任务(协程)。所有异步操作都由这个循环来跑,而每个线程只能有一个事件循环。

  • asyncio.run():这个函数是运行异步程序的入口。它创建并管理事件循环,并在结束后做好清理。请记住,它的设计是每个线程只调用一次。像 FastAPI 这样的框架会替你运行事件循环,另一些场景则需要你自己来运行。

  • 异步 + Python Notebook:Python notebook 是一种特殊情况——事件循环已经在运行了。也就是说你不必自己调用 asyncio.run(),可以直接调用并 await 异步函数。

2. 异步函数与 await

  • 定义异步函数:用 async def 语法定义一个异步函数(协程)。调用异步函数不会立即执行,而是返回一个需要被调度运行的协程对象。

  • 使用 await:在异步函数内部,await 会暂停该函数的执行,直到被等待的任务完成。当你写 await some_fn() 时,函数会把控制权交还事件循环,让其他任务得以被调度和运行。同一时刻只有一个异步函数在执行,它们通过 await 让出控制权来协作。

3. 并发是怎么发生的

  • 协作式并发:虽然你可以调度多个异步任务,但同一时刻只有一个任务在执行。这与真正的并行不同——并行是多个任务同时运行。当任务遇到 await 时,它会挂起自己,让另一个任务得以运行。这使得异步程序非常适合有大量等待的 I/O 密集型任务,例如调用 LLM 和其他服务的 API。

  • 并非真正并行:asyncio 提供的是并发,而不是并行地运行任务。对于需要真正并行的 CPU 密集型工作,请考虑多线程或多进程。LlamaIndex 在多数情况下避免使用多进程,而把选择权交给用户,因为要想做得安全又高效并不容易。

4. 处理阻塞(同步)代码

  • asyncio.to_thread():有时你需要在不冻结异步程序的前提下运行同步(阻塞)代码。asyncio.to_thread() 会把阻塞代码交给一个单独的线程,从而让事件循环继续处理其他任务。请谨慎使用,它会带来一些额外开销,也会让调试变得更困难。

  • 另一种做法:执行器(Executors):你也许还会见到用 loop.run_in_executor() 来处理阻塞函数。

5. 一个实际例子

下面这个例子演示如何用 asyncio 编写并运行异步函数:

import asyncio

async def fetch_data(delay):
    print(f"Started fetching data with {delay}s delay")

    # Simulates I/O-bound work, such as network operation
    await asyncio.sleep(delay)

    print("Finished fetching data")
    return f"Data after {delay}s"

async def main():
    print("Starting main")

    # Schedule two tasks concurrently
    task1 = asyncio.create_task(fetch_data(2))
    task2 = asyncio.create_task(fetch_data(3))

    # Wait until both tasks complete
    result1, result2 = await asyncio.gather(task1, task2)

    print(result1)
    print(result2)
    print("Main complete")

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

BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。