2

这个 Julia 函数似乎效率很低(即使在 Julia 预热之后,也比等效的 Pythran / C++ 代码慢了一个数量级)......

function my_multi_broadcast(a)
    10 * (2*a.^2 + 4*a.^3) + 2 ./ a
end

arr = ones(1000, 1000)
my_multi_broadcast(arr)

我想只是我写得不正确......如何在 Julia 中加速这种“多广播”?我想/希望我不需要花费循环......

在第一个答案后编辑

谢谢!使用我的设置,Pythran 解决方案(就地和不就地)仍然快 1.5 到 2 倍(没有 OpenMP)。有没有办法在 Julia 中激活 SIMD 指令?或者另一种加速此类 CPU 计算的方法?

Python代码:

from transonic import jit

@jit
def broadcast(a):
    return 10 * (2*a**2 + 4*a**3) + 2 / a

@jit
def broadcast_inplace(a):
    a[:] = 10 * (2*a**2 + 4*a**3) + 2 / a

@simd建议后编辑

似乎这@simd不是开箱即用的,即只需在行首添加它。

ERROR: LoadError: LoadError: Base.SimdLoop.SimdError("for loop expected")
Stacktrace:
 [1] compile(::Expr, ::Bool) at ./simdloop.jl:54
 [2] @simd(::LineNumberNode, ::Module, ::Any) at ./simdloop.jl:126
 [3] include at ./boot.jl:317 [inlined]
 [4] include_relative(::Module, ::String) at ./loading.jl:1044
 [5] include(::Module, ::String) at ./sysimg.jl:29
 [6] exec_options(::Base.JLOptions) at ./client.jl:231
 [7] _start() at ./client.jl:425

我想必须扩展 for 循环,但是代码 (i) 变得不那么可读并且 (ii) 不再独立于维度。

似乎我们有一个案例,使用 Pythran 可以比使用 Julia 更快地加速简单的 Python/Numpy 代码(除非有办法在 Julia 中加速?并且未来的 Julia 版本可能会解决这个问题)。有趣的...

4

1 回答 1

13

像这样广播所有操作:

julia> function my_multi_broadcast2(a)
           @. 10 * (2*a^2 + 4*a^3) + 2 / a
       end
my_multi_broadcast2 (generic function with 1 method)

不同之处在于,10 * (2*a.^2 + 4*a.^3) + 2 ./ a您实际上并没有利用广播融合,因为*两个+没有广播。

写作@. 10 * (2*a^2 + 4*a^3) + 2 / a相当于10 .* (2 .* a.^2 .+ 4 .* a.^3) .+ 2 ./ a

这是性能的比较

julia> @btime my_multi_broadcast($arr);
  58.146 ms (18 allocations: 61.04 MiB)

julia> @btime my_multi_broadcast2($arr);
  5.982 ms (4 allocations: 7.63 MiB)

当我们获得大约 10 倍的加速时,它与 Pythran / C++ 相比如何?

最后请注意,如果您可以通过以下方式进行变异arr

julia> function my_multi_broadcast3(a)
           @. a = 10 * (2*a^2 + 4*a^3) + 2 / a
       end
my_multi_broadcast3 (generic function with 1 method)

julia> @btime my_multi_broadcast3($arr);
  1.840 ms (0 allocations: 0 bytes)

它更快并且执行零分配(我不知道您是要arr就地修改还是创建一个新数组,所以我展示了这两种方法)。

于 2018-11-24T18:16:46.343 回答