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

时间:2016-11-07 11:01:04

标签: 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 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):

0.089517 seconds (4.98 k allocations: 15.549 MB, 88.70% gc time)
0.003165 seconds (4 allocations: 160 bytes)

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

我预计vecdot或多或少与通过迭代进行(使用一些额外的长度检查分配等)。

让这更令人困惑:当我单独使用vecdot时(甚至在切片/视图/子数组/无论它们被称为b [:,i]之类),而不将结果插入数组元素中,它会表现与迭代基本相同。我查看了Julia base中的源代码,毫不奇怪,vecdot只是迭代并累积结果。

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

1 个答案:

答案 0 :(得分:3)

b[:,i]分配一个新的Array对象,因此两个版本之间存在很大差异。第一个版本创建了许多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将减少工作量。