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

使用Delphi的TParallel.&For优化哥德巴赫猜想验证为何性能下降?

Delphi TParallel.&For优化哥德巴赫猜想反而变慢的问题分析与解决

问题根源分析

1. 任务粒度过于精细

当前TParallel.&For把每个数(从6到MaxInt-1)都作为独立任务分发,而每个偶数的验证逻辑非常轻量化——尤其是小偶数,循环几次就会命中素数对并Break。线程调度、上下文切换的开销远远超过了单个任务的执行时间,直接导致整体效率下降。

2. 缓存局部性破坏与伪共享

单线程验证时,顺序遍历偶数的方式让IsPrime数组的访问具有极强的连续性,CPU缓存命中率极高。但并行后,多个线程分散访问数组的不同位置,不仅破坏了缓存局部性,还可能引发伪共享(多个线程同时访问同一缓存行的不同数据),导致缓存频繁失效、刷新,大幅增加内存访问开销。

3. 无效的奇数处理

TParallel.&For遍历了所有数,其中一半是奇数,每个任务都要执行ANumber mod 2 <> 0 then Exit的判断,这部分额外逻辑累积起来也是不小的开销。

4. 冗余的素数判断

APrimes是欧拉筛生成的素数表,里面的元素必然是素数,因此IsPrime[Index]的判断完全多余,每次循环多了一次不必要的数组访问。

优化方案与代码调整

1. 增大任务粒度,保持缓存局部性

使用TParallel.&For的范围分区器重载版本,让每个线程处理连续的偶数块,既减少线程切换次数,又能利用CPU缓存的局部性优势。

2. 直接遍历偶数,跳过奇数

从6开始,步长设为2,直接遍历所有偶数,避免对奇数的无效判断。

3. 移除冗余的素数判断

删掉IsPrime[Index]的判断,因为APrimes中的元素都是预先生成的素数。

优化后的代码

procedure GoldBachCheckParallel(APrimes: TArray<Int64>; IsPrime: TArray<Boolean>);
var
  MaxEven: Int64;
begin
  // 确保上限是偶数
  MaxEven := IfThen(MaxInt mod 2 = 0, MaxInt, MaxInt - 1);
  // 使用范围分区器,每个线程处理连续的10000个偶数块,提升缓存命中率
  TParallel.&For(6, MaxEven, 2, TPartitioner.CreateRange(6, MaxEven, 2, 10000), 
    procedure(ANumber: Int64)
    var
      Prime: Int64;
    begin
      for Prime in APrimes do
      begin
        if IsPrime[ANumber - Prime] then
          Break;
        if Prime * Prime > ANumber then
          Break;
      end;
    end);
end;

额外优化建议

  • 如果APrimes数组体积很大,可以考虑按CPU缓存行大小对齐,进一步减少伪共享的影响;
  • 预先计算APrimes中小于等于√MaxInt的素数子集,避免每次循环计算Prime * Prime;
  • 对于大偶数,验证到ANumber/2即可停止,因为素数对是对称的,能减少一半的循环次数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 02:15:04