【问题标题】:@parallel vs. native loops in julia@parallel 与 julia 中的本机循环
【发布时间】:2017-08-15 05:10:31
【问题描述】:

我运行了一些示例并得到了一些结果。我得到了大量的迭代,我们可以得到一个好的结果,但是对于更少的迭代,我们可以得到一个更差的结果。

我知道有一点开销,这绝对没问题,但是有什么方法可以比顺序方式更好地以并行方式运行一些迭代次数更少的循环?

x = 0
@time for i=1:200000000
    x = Int(rand(Bool)) + x
end

7.503359 秒(200.00 M 分配:2.980 GiB,2.66% gc 时间)

x = @time @parallel (+) for i=1:200000000
    Int(rand(Bool))
end

0.432549 秒(3.91 k 分配:241.138 KiB)

我在这里并行得到了很好的结果,但在下面的例子中没有。

x2 = 0
@time for i=1:100000
    x2 = Int(rand(Bool)) + x2
end

0.006025 秒(98.97 k 分配:1.510 MiB)

x2 = @time @parallel (+) for i=1:100000
    Int(rand(Bool))
end

0.084736 秒(3.87 k 分配:239.122 KiB)

【问题讨论】:

  • 我猜在一定次数的迭代之后使用线程的开销是值得的
  • @MauricePerry 这不是线程,而是多处理。多处理比线程有更多的开销,因为它是完全异步的,甚至可以在其他计算机上拥有进程。 @ReD,您需要在每个流程上进行“足够”的工作才能使多处理获得回报。否则你应该看看通过Threads.@threads使用线程。
  • 您介意一些术语吗?这不是 [Parallel] 进程执行,而是一个 [Concurrent] 调度 -- 正如定义的 (cit:) -- [Parallel] 处理是,与仅 [并发] 处理形成鲜明对比的是,保证启动/执行/完成以并行方式执行的所有线程级和/或指令级任务,并保证完成同时执行的代码路径。 如果是真正的 [Parallel] 执行,应该有 200E+6 个 CPU 核心来允许这种 [Parallel] 执行。不在这里,@parallel 装饰器永远不会创建 CPU
  • @ReD 有关 (SEQ:setup-overheads, PAR:HPC-payload) 加速的详细信息,请不要犹豫查看一篇关于(开销感知)Amdahl-Law + 数据关于 Point-of-Diminishing-Returns 的帖子,如 >>> stackoverflow.com/a/45562881中类似动机问题中可实现的加速中所述>

标签: julia


【解决方案1】:

并行做事总是效率低下。这是因为并行处理总是有同步的开销。无论如何,希望是比纯顺序调用(一台计算机,单核)更早地获得结果

你的数字很惊人,我找到了原因。

首先,允许使用所有内核,进入REPL

julia> nworkers
4

# original case to get correct relative times
julia> x = 0
julia> @time for i=1:200000000
          x = Int(rand(Bool)) + x
       end

7.864891 seconds (200.00 M allocations: 2.980 GiB, 1.62% gc time)

julia> x = @time @parallel (+) for i=1:200000000
          Int(rand(Bool))
       end
0.350262 seconds (4.08 k allocations: 254.165 KiB)
99991471

# now a correct benchmark
julia> function test()
         x = 0
         for i=1:200000000
           x = Int(rand(Bool)) + x
         end
       end
julia> @time test()
0.465478 seconds (4 allocations: 160 bytes)

发生了什么?

您的第一个测试用例使用全局变量 x。这太慢了。案例访问 200 000 000 次慢变量。

在第二个测试用例中,全局变量 x 只分配了一次,因此不考虑性能不佳

在我的测试用例中没有全局变量。我使用了一个局部变量。局部变量更快(由于更好的编译器优化)

【讨论】:

    【解决方案2】:

    问:有什么方法可以比顺序方式更好地以并行方式运行一些迭代次数更少的循环?


    答:是的。

    1)如果这一切都有意义的话,可以获得更多资源(用于计算的处理器、用于存储的内存)

    2) 更智能地安排工作流程 - 从基于寄存器的代码中受益,在每次第一次提取时利用缓存行的大小,在可能的情况下部署重用(努力工作?是的,它是一项艰苦的工作,但为什么要重复支付 150+ [ns] 而不是一次性支付并在约 30 [ns] 延迟成本(如果 NUMA 允许的话)内重复使用对齐良好的相邻单元?)。更智能的工作流程通常还意味着代码重新设计,以增加由此产生的汇编代码“计算密度”并调整代码,以便更好地绕过(优化)超标量处理器硬件设计技巧,这些技巧是在高度调整的 HPC 计算负载中没有用/有积极的好处。

    3) 避免陷入任何阻塞资源和瓶颈(中心奇点,例如主机的硬件独特的随机源、IO 设备等)

    4) 熟悉优化编译器的内部选项和“快捷方式”——有时会以延长运行时间为代价生成反模式

    5) 从底层操作系统的调整中获得最大收益。不这样做,您的优化代码仍然在 O/S 调度程序的队列中等待(并且很多)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多