Pandas 与 PySpark
不同 workload 运行对比

这组实验不只回答“谁更快”:优势出现在哪类任务、为什么计算与完整处理会给出相反的选择、哪些差距还不足以下结论。下面按总体趋势、任务差异、计时口径、扩展表现、工作量结构和证据强度逐层展开。

01 / 总体趋势 · 规模改变优势范围

PySpark 的优势随规模扩大,但不是统一切换

从 100 万、1000 万到 1 亿行,PySpark 计算耗时更低的任务由 0 → 6 → 9 / 12 增加,端到端则为 0 → 2 → 12 / 12。到 1 亿行,完整处理的耗时差达到 3.27–5.77 倍。

选型启示:规模是第一层筛选,任务类型与计时范围决定最后的选择。这里的“胜出”按中位数计数,也包含接近持平的任务。

02 / 任务差异 · 优势出现的规模不同

排序更早体现收益,不能用一个行数阈值选引擎

1000 万行时,只有数值排序和字符串排序的端到端耗时是 PySpark 更低,分别只需 pandas 耗时的 80% / 82%。同规模去重虽在计算上快 2.19 倍,端到端却是 pandas 更快(5.54 vs 13.39 秒)。

选型启示:三档规模只能给出优势变化的区间,不能推导“超过某个固定行数就换 PySpark”。

03 / 计时反转 · 优化对象决定结论

算子更快,也可能让完整任务等得更久

1 亿行过滤,pandas 计算为 9.26 秒,低于 PySpark 的 14.57 秒;端到端却是 110.36 vs 24.78 秒,PySpark 快 4.45 倍。

选型启示:数据已驻留、连续做运算时参考计算模式;从启动到结果文件交付时参考端到端。该反转说明只优化算子不足以预测完整处理时间,具体原因需阶段证据;两种独立运行不能相减拆分开销。

04 / 扩展表现 · 小样本不能线性外推

数据增加 100 倍,耗时并非都增加 100 倍

从 100 万到 1 亿行,求和与流水线的 pandas 计算耗时分别增加 105.8 / 103.7 倍,PySpark 则为 3.52 / 3.64 倍。小规模的耗时排序因此不能直接外推到大规模。

选型启示:至少用接近业务规模的数据验证。固定成本摊薄与并行执行是可能解释,但这些曲线不能单独分离两者,也不能证明更大规模仍按同样比例增长。

05 / 工作量结构 · 同样行数不等于同样负载

真正要看的是“处理什么、留下多少结果”

1 亿行时,流水线只选 3 列、筛选约 1% 的输入再聚合,最终输出 100 行、2 列;过滤任务保留全列,输出约 5000 万行、10 列。PySpark 计算分别为 1.60 / 14.57 秒;流水线相对 pandas 的优势为 7.94 倍。

选型启示:输入行数之外,还要对齐筛选比例、列宽和输出规模。不能将这个“先筛选再聚合”的结果泛化为所有多步骤流水线;这里并非只改变一个因素的对照实验。

06 / 证据强度 · 接近持平不宜硬分胜负

约 3% 的中位数差距,不足以支持迁移决策

1 亿行的小表内连接与大表内连接,计算中位数仅相差约 3.2% / 2.9%(以 PySpark 耗时为分母)。大表内连接的两次值范围为 pandas 28.80–34.74 秒、PySpark 30.67–31.07 秒,两者重叠;小表连接也一样。

选型启示:将这两项计算表现视为接近,增加独立重复再判断。观测范围不是置信区间;端到端的明显差距应单独评估。

查看以上结论的数据依据
均为原正式批次、24 核;中位数及两次实测,单位:秒。
规模任务模式pandasPySpark
1000 万行数值排序计算12.1898两次实测:12.5241 / 11.85554.0756两次实测:4.0480 / 4.1033
1000 万行数值排序端到端24.7939两次实测:24.8109 / 24.777019.7502两次实测:19.5708 / 19.9297
1000 万行字符串排序计算12.0973两次实测:12.1704 / 12.02414.4150两次实测:4.2916 / 4.5383
1000 万行字符串排序端到端24.3391两次实测:24.2715 / 24.406620.0108两次实测:19.8607 / 20.1609
1000 万行去重计算1.8722两次实测:1.8740 / 1.87050.8537两次实测:0.8785 / 0.8290
1000 万行去重端到端5.5381两次实测:5.5173 / 5.559013.3922两次实测:13.4520 / 13.3325
10000 万行过滤计算9.2647两次实测:8.9730 / 9.556414.5749两次实测:14.4408 / 14.7091
10000 万行过滤端到端110.3616两次实测:111.2124 / 109.510824.7810两次实测:24.9261 / 24.6359
100 万行求和计算0.0295两次实测:0.0296 / 0.02940.2334两次实测:0.1951 / 0.2716
10000 万行求和计算3.1204两次实测:2.7580 / 3.48290.8223两次实测:0.8403 / 0.8043
100 万行组合任务计算0.1227两次实测:0.1224 / 0.12300.4397两次实测:0.4665 / 0.4129
10000 万行组合任务计算12.7265两次实测:12.1639 / 13.28911.6025两次实测:1.7694 / 1.4356
10000 万行小维表连接计算29.3598两次实测:27.1169 / 31.602730.3452两次实测:29.7313 / 30.9591
10000 万行内连接计算31.7701两次实测:28.7994 / 34.740730.8703两次实测:31.0745 / 30.6661

下载结论计算依据、输出规模与原始观测 JSON

结论基于本次单机 24 核、12 个 workload 的正式耗时中位数;每配置两次重复。下方可切换数据规模及单核对照,较小差异不代表统计显著。

同步应用于总览和全部 workload
01 / 耗时总览

计算耗时:数据就绪后,算出结果要多久?

数据已加载并完成预热,从开始执行任务计到完整结果物化。不包括容器启动、加载、预热和结果写盘。

端到端耗时:从启动到结果落盘,要多久?

从启动容器开始,覆盖数据加载、计算、Parquet 结果输出以及 fsync(确保写入完成),用于比较一次完整任务的等待时间。

例:读取一份订单文件,把金额列求和,再把总金额保存为结果文件。同样的任务,两种模式的“秒表”覆盖不同步骤:

计算模式:先启动环境、读入订单并完成预热,再开始计时 → 对金额列求和,直到总金额真正算出 → 停止计时。之后保存结果的时间不计入。它回答的是:数据已经准备好,执行这次运算有多快?

端到端模式:开始计时 → 启动容器和引擎 → 读取订单 → 求和 → 将结果写为 Parquet 文件并完成 fsync → 停止计时。它回答的是:从启动这次任务,到拿到落盘的结果,一共要等多久?

两种模式来自独立运行,并非同一次运行的嵌套计时;不要直接相减来估计启动或 I/O 耗时。下图条形及数值表示两次测量的中位数,实心点 ● / 空心点 ○ 分别表示第 1 / 2 次真实测量。

任务按相同顺序纵向排列,每个任务用两根横向条形比较引擎。同图所有任务共用从 0 开始的线性时间轴;端到端与计算两张图的横轴范围分别设置,请按秒数比较。点击各图图例可筛选引擎,两次原始耗时见完整数据表。每配置只有两次重复,小差异不代表统计显著。

02 / 按任务追踪资源 12 个 workload

同一起点,保留各自的真实时长。

每次运行各自从计时开始对齐到 0 秒:计算模式从加载、预热后开始,端到端模式从容器启动开始。曲线不拉伸、不平均,也不延长到其他运行结束。

CPU、内存与 I/O 均为整机观测,包含后台服务。33 组短计算配置已以 5 ms(目标 200 Hz)独立补测,132 次全部通过,每项至少 4 个有效点。选择“计算”查看高频计算曲线,选择“端到端”查看原正式运行(约 1 秒采样),每次只显示一种模式。两者来自不同运行,不能拼接成一次执行。原计算曲线与 profiling 可展开查看。另有单核 8 个任务、32 次独立补测,耗时与资源均来自这些新运行;单核视图共 12 个任务。
同步切换所有任务,时间轴按所选模式自动调整。
先选规模,再选择任务;四项资源图共享时间范围。
01求和sum
02过滤filter
03去重distinct
04数值排序sort_numeric
05字符串排序sort_string
06低基数分组group_low
07多列分组group_multi
08高基数分组group_high
09小维表连接join_small
10内连接join_inner
11左连接join_left
12组合任务pipeline
03 / 完整数据 84 组 · 原正式 304 次 + 单核补测 32 次 每个结论,都能回到原始观测。
单位:秒。点击第 1 / 2 次耗时可打开该次运行的原始指标。
行数任务模式核数来源pandas ①pandas ②中位数PySpark ①PySpark ②中位数
1000000求和计算24原正式0.02960.02940.02950.19510.27160.2334
1000000求和端到端24原正式1.58181.54751.564611.470311.143311.3068
1000000过滤计算24原正式0.07090.07030.07060.65760.55330.6054
1000000过滤端到端24原正式1.99461.97911.986811.417511.590411.5039
1000000去重计算24原正式0.18140.18060.18100.47770.58430.5310
1000000去重端到端24原正式1.70031.69081.695612.853712.909112.8814
1000000数值排序计算24原正式0.60000.60140.60071.24451.24651.2455
1000000数值排序端到端24原正式2.92182.92372.922815.654515.285215.4699
1000000字符串排序计算24原正式0.50250.48280.49261.23151.25031.2409
1000000字符串排序端到端24原正式2.78752.79392.790715.183214.809114.9962
1000000低基数分组计算24原正式0.07290.07490.07390.41000.49510.4526
1000000低基数分组端到端24原正式1.58721.58621.586712.522012.409312.4657
1000000多列分组计算24原正式0.22300.22120.22210.57320.58280.5780
1000000多列分组端到端24原正式1.74831.74141.744913.549613.448113.4988
1000000高基数分组计算24原正式0.04950.04880.04920.44580.51700.4814
1000000高基数分组端到端24原正式1.55351.56631.559913.010912.963012.9869
1000000小维表连接计算24原正式0.23740.23400.23571.13291.20411.1685
1000000小维表连接端到端24原正式2.63012.61352.621812.536112.472512.5043
1000000内连接计算24原正式0.22480.21970.22220.98571.01491.0003
1000000内连接端到端24原正式2.53742.55222.544813.264913.303513.2842
1000000左连接计算24原正式0.14050.14270.14161.08441.01081.0476
1000000左连接端到端24原正式2.51222.48252.497413.043113.215013.1290
1000000组合任务计算24原正式0.12240.12300.12270.46650.41290.4397
1000000组合任务端到端24原正式1.62171.67671.649212.984812.903612.9442
10000000求和计算24原正式0.29410.29650.29530.41330.41740.4154
10000000求和端到端24原正式3.95403.93633.945112.174412.006812.0906
10000000过滤计算24原正式0.74810.75050.74931.35631.20781.2820
10000000过滤端到端24原正式8.89208.89288.892414.228714.251814.2402
10000000去重计算24原正式1.87401.87051.87220.87850.82900.8537
10000000去重端到端24原正式5.51735.55905.538113.452013.332513.3922
10000000数值排序计算24原正式12.524111.855512.18984.04804.10334.0756
10000000数值排序端到端24原正式24.810924.777024.793919.570819.929719.7502
10000000字符串排序计算24原正式12.170412.024112.09734.29164.53834.4150
10000000字符串排序端到端24原正式24.271524.406624.339119.860720.160920.0108
10000000低基数分组计算24原正式0.77250.77320.77290.57670.62740.6020
10000000低基数分组端到端24原正式4.56814.41644.492312.939812.901712.9208
10000000多列分组计算24原正式2.08772.03552.06160.99480.89670.9458
10000000多列分组端到端24原正式5.73975.80195.770813.911014.209514.0602
10000000高基数分组计算24原正式0.78210.66800.72500.81110.92100.8660
10000000高基数分组端到端24原正式4.43304.38214.407614.149014.205314.1771
10000000小维表连接计算24原正式2.70972.69962.70472.52483.18772.8563
10000000小维表连接端到端24原正式15.741315.615315.678316.397315.186115.7917
10000000内连接计算24原正式2.69022.53592.61314.21964.17344.1965
10000000内连接端到端24原正式14.795114.817814.806419.017518.689918.8537
10000000左连接计算24原正式1.46341.43521.44934.27733.89934.0883
10000000左连接端到端24原正式15.055514.559114.807320.286919.410319.8486
10000000组合任务计算24原正式1.22931.22761.22840.57330.59370.5835
10000000组合任务端到端24原正式4.89825.05204.975113.031213.179613.1054
100000000求和计算24原正式2.75803.48293.12040.84030.80430.8223
100000000求和端到端24原正式48.709748.212148.460912.634512.680512.6575
100000000过滤计算24原正式8.97309.55649.264714.440814.709114.5749
100000000过滤端到端24原正式111.2124109.5108110.361624.926124.635924.7810
100000000去重计算24原正式18.325718.287518.30664.35324.23544.2943
100000000去重端到端24原正式66.418665.809066.113815.709715.590715.6502
100000000数值排序计算24原正式152.0517147.4978149.774736.210236.333236.2717
100000000数值排序端到端24原正式307.4599304.0218305.740951.725954.204152.9650
100000000字符串排序计算24原正式175.0588173.4315174.245245.433046.324045.8785
100000000字符串排序端到端24原正式330.3462321.2228325.784564.896565.034964.9657
100000000低基数分组计算24原正式7.76407.54247.65322.06311.78771.9254
100000000低基数分组端到端24原正式54.714154.224554.469314.140013.938214.0391
100000000多列分组计算24原正式21.166920.962321.06464.54664.40424.4754
100000000多列分组端到端24原正式69.669369.039769.354517.304016.907317.1057
100000000高基数分组计算24原正式12.388311.918112.15325.39525.35705.3761
100000000高基数分组端到端24原正式69.800458.581764.191019.542919.720019.6315
100000000小维表连接计算24原正式27.116931.602729.359829.731330.959130.3452
100000000小维表连接端到端24原正式199.8728191.0975195.485139.065239.950439.5078
100000000内连接计算24原正式28.799434.740731.770131.074530.666130.8703
100000000内连接端到端24原正式180.0142174.2984177.156343.797146.599745.1984
100000000左连接计算24原正式16.381117.426016.903534.550734.093934.3223
100000000左连接端到端24原正式174.9924180.1277177.560149.420346.814048.1171
100000000组合任务计算24原正式12.163913.289112.72651.76941.43561.6025
100000000组合任务端到端24原正式68.677066.972267.824614.733114.513014.6231
10000000求和计算1原正式0.28820.29520.29171.32311.52471.4239
10000000数值排序计算1原正式10.937810.972010.954956.556154.825955.6910
10000000高基数分组计算1原正式0.65270.65030.65152.95903.16513.0621
10000000内连接计算1原正式2.56252.54622.554456.405052.697154.5510
10000000过滤计算1单核独立补测0.71420.71220.713217.933217.653117.7931
10000000去重计算1单核独立补测1.84401.84031.84225.18604.98585.0859
10000000字符串排序计算1单核独立补测11.161011.229011.195065.816764.817765.3172
10000000低基数分组计算1单核独立补测0.75800.77440.76622.55762.82442.6910
10000000多列分组计算1单核独立补测2.04382.03602.03995.82375.84505.8344
10000000小维表连接计算1单核独立补测2.66132.64942.655334.421635.504934.9633
10000000左连接计算1单核独立补测1.38351.37901.381257.464758.903458.1841
10000000组合任务计算1单核独立补测1.21421.21371.21392.43042.46632.4483

原正式完整精度 JSON · 单核独立补测 JSON · 逐次运行与原始离线指标

04 / 方法与证据 统计口径保持不变

两种计时,回答不同问题

计算耗时排除启动、加载、预热和输出落盘,计时包含完整结果物化。端到端耗时包含容器启动、加载、计算、Parquet 输出及 fsync。两者来自独立运行。

资源口径与采样边界

CPU 为整机执行核数,不含 iowait / steal;内存为 MemTotal − MemAvailable;磁盘为 sda。CPU / I/O 的前后采样点都须落在计时窗口内。原约 1 秒采样超过 2.2 秒的缺口断开;高频采样的被拒绝区间及超过 20 ms 的间隔断开。无平滑、无插值,无样本留空。

重复顺序与调度修订

正式矩阵为 3 规模 × 12 任务 × 2 引擎 × 2 模式 × 2 次 = 288 次,加单核 16 次。按原 seed108 随机队列每配置保留最先两次;第 1 / 2 次表示保留顺序,不等于原 repeat 标签。

验收与文件保留

304 次正确性通过。原始结果、采集归档、输入校验和与调度修订已验收。大输出保留于测试机,未包含在默认本地下载中。补充 profiling 不替代正式观测。

高频补测的范围与限制

33 组计算配置,两引擎各两次,共 132 次;按原计算曲线任一资源不足 5 点选取。与原实验使用相同 worker、镜像、数据及正确性签名。补测只用于资源观测,正式耗时仍取原 304 次结果。计算曲线与端到端曲线按各自计时开始对齐为 0 秒。

每项至少 4 点,CPU / I/O 首尾有效点覆盖至少 45% 计算时长。Linux /proc CPU 计账粒度不会随采样频率提高;数毫秒尖峰不能解释为精确 CPU 峰值。零 I/O 可能是真实零值。

采集开销与证据

采集开 / 关门槛共 8 次:每引擎各两次开启、两次关闭。耗时中位数比为 pandas 1.010、PySpark 0.926,均低于 1.25 门槛;门槛运行的采集 CPU 占单逻辑核约 5.5%–7.9%。仅两次重复不能证明零开销,逐次采集成本见运行明细。

旧资源补测的 24 核配置中,采集器使用逻辑核 47,与 worker 核 23 共享物理核。补测原始快照、采样 CSV、时间窗口及阶段事件均可查。output / scratch 保留测试机,未下载。

132 次补测验收 · 8 次开销门槛 · 补测曲线清单 · 补测计划 · 补测证据与复现说明

单核任务补全 · 独立来源

1000 万行、1 核、计算模式新增 8 个任务 × 2 引擎 × 2 次,共 32 次。与原单核 4 个任务合计 12 个;原正式 304 次不变。新补测的耗时与资源来自同一次运行,区别于旧 132 次仅用于资源的补测。每行来源及逐次证据可在完整数据表中查看。

worker 固定 CPU0,Spark local[1] / shuffle1,96g heap、128 GiB 内存。跨核数比较同时改变了并行度与 shuffle 分区,不能把差异全部归因于 CPU 数量。

单核采集与归档

采集器目标间隔 5 ms,位于 CPU47,与 worker CPU0 物理隔离。沿用原 24 核求和开销门槛,不声称为新的单核开销估计。32 次正确性签名均匹配原同任务参考;每项资源最少 141 点,最低覆盖率 98.28%。output / scratch 保留远端,未下载。

32 次本地核验 · 单核补测曲线清单 · 补测计划 · 证据包 SHA 与导出凭据 · 逐文件 SHA 清单

查看冻结版本与复现入口

Campaign:20261025T130534Z-full

Worker source SHA-256:68ab7d2564bcb09b20271dfa49f88ce8023df6f097c74c06fba624cf5b2cf3b3

高频补测 Campaign:20261026-resource-highfreq-supplement;原始计划与采集入口随离线包附带,已完成实验不得重复启动。

新 campaign 复现:python3 .runtime/two-repeat-schedule.py --root . --campaign NEW_ID --reproduce