You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Polars中collect_all与LazyFrame.collect的性能差异及优化问询

关于Polars延迟执行与立即执行拼接的性能差异问题

先看以下示例代码:

import time
import numpy as np
import polars as pl

n_index = 1000
n_a = 10
n_b = 500
n_obs = 5000000

df = pl.DataFrame(
    {
        "id": np.random.randint(0, n_index, size=n_obs),
        "a": np.random.randint(0, n_a, size=n_obs),
        "b": np.random.randint(0, n_b, size=n_obs),
        "x": np.random.normal(0, 1, n_obs),
    }
).lazy()

dfs = [
    pl.DataFrame(
        {
            "id": np.random.randint(0, n_index, size=n_obs),
            "a": np.random.randint(0, n_a, size=n_obs),
            f"b_{i}": np.random.randint(0, n_b, size=n_obs),
            "x": np.random.normal(0, 1, n_obs),
        }
    ).lazy()
    for i in range(50)
]

res = [
    df.join(
        dfs[i], left_on=["id", "a", "b"], right_on=["id", "a", f"b_{i}"], how="inner"
    )
    .group_by("a", "b")
    .agg((pl.col("x") * pl.col("x_right")).sum().alias(f"x_{i}"))
    for i in range(50)
]

需求为处理多个DataFrame并计算,最后将所有结果拼接。上述代码构建了包含所有计算结果的列表res。

针对结果拼接,我尝试了两种方案:

方案1

start = time.perf_counter()
res2 = pl.collect_all(res)
res3 = res2[0]
for i in range(1, 50):
    res3 = res3.join(res2[i], on=["a", "b"])
time.perf_counter() - start

方案2

start = time.perf_counter()
res4 = res[0]
for i in range(1, 50):
    res4 = res4.join(res[i], on=["a", "b"])
res4 = res4.collect()
time.perf_counter() - start

方案1先执行collect_all再逐个拼接DataFrame;方案2全程采用延迟执行,最后才调用collect。

据我了解,collect会在底层做优化,原本预期两种方案性能相近,但测试结果显示方案2耗时是方案1的两倍(32核系统下21s vs 10s)。

因此想请教:

  • 这种性能差异是否符合预期?我的实现方式是否存在低效问题?
  • 方案2的优势是全程延迟执行,适合需要提供全延迟API、让用户后续自主操作的场景,但性能损耗过大。有没有办法在保持全延迟API的同时,达到接近方案1的性能?

内容的提问来源于stack exchange,提问作者lebesgue

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 03:15:26