Julia 将结果插入数组时,vecdot会生成许多分配

Julia 将结果插入数组时,vecdot会生成许多分配,julia,Julia,这是在其他更复杂的代码中出现的,但我已经编写了我认为是最低限度的工作示例 我发现这种行为令人惊讶: function byvecdot!(a,b,c) for i in eachindex(a) a[i] = vecdot(b[:,i],c[:,i]) end return end function byiteration!(a,b,c) for i in eachindex(a) a[i] = 0.0 for

这是在其他更复杂的代码中出现的,但我已经编写了我认为是最低限度的工作示例

我发现这种行为令人惊讶:

function byvecdot!(a,b,c)
    for i in eachindex(a)
        a[i] = vecdot(b[:,i],c[:,i])
    end
    return 
end

function byiteration!(a,b,c)
    for i in eachindex(a)
        a[i] = 0.0
        for j in 1:size(b,1)
            a[i] += b[j,i]*c[j,i]
        end
    end
    return
end

a = zeros(Float64,1000)
b = rand(Float64,1000,1000)
c = rand(Float64,1000,1000)

@time byvecdot!(a,b,c)
fill!(a,0.0) # Just so we have exactly the same environment
@time byiteration!(a,b,c)
结果(JIT预热后):

我对分配的数量比时间更惊讶(前者肯定会导致后者,特别是考虑到所有gc时间)

我希望vecdot与通过迭代实现的方法大致相同(对于长度检查等有一些额外的分配)

更让人困惑的是:当我单独使用vecdot时(即使在切片/视图/子阵列/它们被称为b[:,I]的任何东西上),没有将结果插入数组元素,它的行为基本上与迭代相同。我查看了Julia base中的源代码,毫不奇怪,vecdot只是在迭代并累积结果


我的问题是:有人能向我解释一下,当我尝试将vecdot插入数组元素时,为什么vecdot会生成这么多(不必要的)分配?我在这里没有掌握什么机制?

b[:,I]
分配了一个新的
数组
对象,因此这两个版本之间存在很大差异。第一个版本创建了许多GC必须跟踪和释放的临时文件。另一种解决办法是

function byvecdot2!(a,b,c)
    for i in eachindex(a)
        a[i] = vecdot(view(b,:,i),view(c,:,i))
    end
    return 
end

视图也会分配,但比
b[:,1]
创建的完整副本要少得多,因此GC将做更少的工作。

我应该注意,我发现vecdot中的累加器需要1000个分配,然后返回。但是其他4000个拨款呢?啊,谢谢,这是有道理的;你的例子正是我心目中所希望的。我想我一定是把自己弄糊涂了,以为切片总是能产生视图。感谢您快速清晰的回复!
function byvecdot2!(a,b,c)
    for i in eachindex(a)
        a[i] = vecdot(view(b,:,i),view(c,:,i))
    end
    return 
end