Polars中两种等价计算方法的并行性能差异与原因探究
Polars两种计算方法的并行性与性能差异分析
先直接给结论:两种方法在并行性上存在差异,方法2性能更优的核心原因是Polars的查询优化器对表达式做了化简,同时避免了中间列的内存开销,而非单线程执行。
一、并行性差异细节
方法1:两次
select的执行逻辑是:- 第一步
select中,计算x_1 = a+b和x_2 = b+c,这两个计算确实可以并行——因为它们依赖的原始列是独立的,Polars会用多线程同时处理这两个列运算。 - 第二步
select需要读取第一步生成的两个中间列x_1和x_2,再求和得到target,这一步的列运算本身也是多线程,但需要先从内存加载中间列,有额外开销。
- 第一步
方法2:看似是嵌套表达式,但Polars的Lazy优化器会先对表达式做化简:
(a + b) + (b + c) → a + 2*b + c化简后的表达式会拆分为三个独立的列运算:
a、2*b、c,这三个部分同样可以并行计算,之后再将结果相加。整个过程没有中间列的存储,直接在原始列上完成所有运算。
二、性能差异的核心原因
表达式化简减少运算步骤
方法1需要3次加法运算(a+b、b+c、x1+x2),而方法2被化简后只需要2次核心运算(2*b、a+2b+c),直接减少了一次大规模列运算的开销。避免中间列的内存开销
方法1会生成两个1亿行的中间列x_1和x_2,按int64类型计算,每个列占用800MB内存,两个就是1.6GB。这些中间列需要写入内存再读取,不仅占用额外内存,还会增加内存读写的延迟。而方法2全程不需要存储中间结果,直接在原始列上做计算,内存效率更高。缓存友好性提升
方法2直接操作原始列,数据更容易被CPU缓存命中;方法1的中间列写入内存后,再次读取时可能已经被挤出缓存,导致CPU需要从内存甚至磁盘加载数据,进一步增加延迟。
验证方式
你可以用explain()查看两种方法的优化后查询计划,直观看到差异:
# 查看方法1的计划 print(df.select(x_1=pl.col("a")+pl.col("b"), x_2=pl.col("b")+pl.col("c")).select(target=pl.col("x_1")+pl.col("x_2")).explain()) # 查看方法2的计划 print(df.select(target=(pl.col("a")+pl.col("b"))+(pl.col("b")+pl.col("c"))).explain())
内容的提问来源于stack exchange,提问作者thoooooooomas
相关产品推荐
相关产品推荐

