Julia 为什么数组+;=(没有@)产生这么多内存分配?

Julia 为什么数组+;=(没有@)产生这么多内存分配?,julia,Julia,我不明白为什么数组的+=操作会产生如此多的内存分配,但在应用@时它会得到修复 function loop() a = randn(10) total = similar(a) for i=1:1000 total += a end end function loopdot() a = randn(10) total = similar(a) for i=1:1000 @. total += a

我不明白为什么数组的+=操作会产生如此多的内存分配,但在应用@时它会得到修复

function loop()
    a = randn(10)
    total = similar(a)

    for i=1:1000
        total += a
    end
end

function loopdot()
    a = randn(10)
    total = similar(a)

    for i=1:1000
        @. total += a
    end
end


loop()
loopdot()

Profile.clear_malloc_data()

loop()
loopdot()
产生

160000         total += a


total+=a
total=a+total
相同,后者是一种矢量化操作,如:

out = similar(a)
for i in eachindex(a)
  out[i] = total[i] + a[i]
end
total = out
因为内部是

total = +(total,a)
这与MATLAB、Python或R一样,因此有一个临时数组分配给矢量化操作,然后
=
total
的引用设置为这个新数组。这就是为什么矢量化操作比传统的低级循环速度慢的原因,也是为什么使用NumPy之类的东西可以比Python更快,但不能完全达到C(因为这些临时性!)

@。总计+=a
与总计相同。=total.+a。说明在Julia中,通过匿名函数进行语义点融合,因此对应于执行以下操作:

# Build an anonymous function for the fused operation
f! = (a,b,c) -> (a[i] = b[i] + c[i])
# Now loop it, since it's `.=` don't make a temporary
for i in eachindex(a)
  f!(total,total,a)
end
它在不创建临时数组的情况下就地更新
total


Julia中的融合在语义上发生:点状操作转换为匿名函数加上
广播调用(本质上就是我在那里写的循环)是在解析时完成的,并且匿名函数是编译的,这样做是有效的。出于其他原因,这也是非常有用的。通过重载
广播在通用
f,这就是自动构建高效单内核的方式,这些内核在GPU上进行就地更新。这与MATLAB、Python和R相反,在MATLAB、Python和R中,不同的矢量化函数被视为不同的函数调用,因此必须计算返回值,从而计算临时数组。

@
是一个宏,用于将
广播应用于整个表达式或代码块的运算符时,请注意,在您的简单示例中,
@。total+=a
等于
total.+=a
,正如Chris进一步解释的那样,这与
total.=total.+a
相同Chris对你的问题给出了一个极好且彻底的答案。有帮助吗?
# Build an anonymous function for the fused operation
f! = (a,b,c) -> (a[i] = b[i] + c[i])
# Now loop it, since it's `.=` don't make a temporary
for i in eachindex(a)
  f!(total,total,a)
end