如何在Julia中加速多个广播 这个朱丽亚函数似乎相当低效(比Pythran / C++代码更慢一个数量级,即使在朱丽亚预热之后)…

如何在Julia中加速多个广播 这个朱丽亚函数似乎相当低效(比Pythran / C++代码更慢一个数量级,即使在朱丽亚预热之后)…,julia,pythran,Julia,Pythran,我想只是我写得不对。。。在茱莉亚,怎样才能加速这种“多重广播”?我想/希望我不需要花费这些循环 在第一个答案后编辑 谢谢大家!!在我的设置中,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

我想只是我写得不对。。。在茱莉亚,怎样才能加速这种“多重广播”?我想/希望我不需要花费这些循环

在第一个答案后编辑 谢谢大家!!在我的设置中,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)不再独立于维度


似乎我们有这样一种情况,简单的Python/Numpy代码可以用Pythran比Julia更快地得到加速(除非Julia中有加速的方法?将来的Julia版本可能会解决这个问题)。有趣的…

广播所有这样的操作:

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)
<> Pythran与C++相比,我们得到了大约10x的加速比?

最后,请注意,如果您可以通过编写以下命令在适当的位置变异
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
,还是创建一个新的数组,所以我展示了这两种方法)。

实际上,您说的是“
@”。10…
相当于…,然后忘记在括号内点乘法。它应该是
10.*(2.*a.^2.+4.*a.^3.+2./a
DNF-谢谢,修复了。这就是为什么在本例中,
@.
是一件好事。您可以尝试添加
@simd
,如果这还不够,请编写一个手动循环。广播应自动使用simd指令,但目前存在一个性能缺陷,对于这样的大型融合表达式,它不会发生。我希望1.2版能修复它。
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)