Polars单线程下LazyFrame与Eager模式内存占用差异及疑问
Polars LazyFrame 与 Eager 模式内存占用疑问
问题背景
我有若干CSV样例文件,分别用两段Polars代码完成读取、过滤与拼接操作:
LazyFrame版本代码
import os os.environ["POLARS_MAX_THREADS"] = "1" import polars as pl df = pl.concat( [ pl.scan_csv("test.csv").filter(pl.col("x3") > 0), pl.scan_csv("test1.csv").filter(pl.col("x3") > 0), pl.scan_csv("test2.csv").filter(pl.col("x3") > 0), ] ).collect()
Eager模式版本代码
将上述代码中的scan_csv替换为read_csv即可。
原本预期LazyFrame版本内存表现与Eager模式相当,但实际测试中LazyFrame版本内存占用反而更高,且增加核心数后内存占用进一步提升。我通过mprof生成了内存占用随时间变化的图表,现提出两个疑问:
- 该
mprof图表是否能可靠反映内存占用情况? - 这种内存占用情况是否会得到优化,还是惰性求值机制必然导致此现象?
解答
1. mprof图表的可靠性
mprof生成的内存图表是可靠的。它通过定期采样目标进程的内存使用情况生成数据,能准确捕捉Polars处理数据过程中的内存分配、释放波动,包括Lazy模式下查询执行阶段的内存变化,可作为内存占用分析的有效依据。
2. 内存占用高的原因与优化空间
这种内存占用并非惰性求值机制的必然结果,当前写法存在优化空间:
- 当前写法的问题:分别对每个CSV文件生成独立的LazyFrame并执行过滤,再通过
pl.concat合并后collect。这种情况下Polars的查询优化器无法将多个文件的扫描、过滤、拼接操作合并为一条高效流水线,执行时可能需要同时加载多个文件的中间数据;多线程场景下,并行处理多个文件还会导致内存叠加,进一步推高内存占用。 - 优化方案:直接将多个CSV文件路径传入
pl.scan_csv,再统一执行过滤和收集操作,代码如下:
import os os.environ["POLARS_MAX_THREADS"] = "1" import polars as pl df = pl.scan_csv(["test.csv", "test1.csv", "test2.csv"]) \ .filter(pl.col("x3") > 0) \ .collect()
这种写法会让Polars生成单一查询计划,流式处理每个CSV文件,过滤后直接拼接结果,内存占用会和Eager模式相当甚至更低,充分发挥惰性求值的内存优势。
内容的提问来源于stack exchange,提问作者John Hopfensperger
相关产品推荐
相关产品推荐

