要迭代多维数组,建议这样做for index in eachindex(A)
; 见例如
https://groups.google.com/forum/#!msg/julia-users/CF_Iphgt2Wo/V-b31-6oxSkJ
如果A
是标准数组,那么这对应于使用单个整数进行索引,这是访问数组的最快方式(原始问题):
A = rand(3, 3)
for i in eachindex(A)
println(i)
end
Run Code Online (Sandbox Code Playgroud)
但是,如果A
是一个更复杂的对象,例如子阵列,那么eachindex(A)
将为您提供一个不同的,高效的访问对象:
julia> for i in eachindex(slice(A, 1:3, 2:3))
println(i)
end
Run Code Online (Sandbox Code Playgroud)
给
CartesianIndex{2}((1,1))
CartesianIndex{2}((2,1))
Run Code Online (Sandbox Code Playgroud)
等等
splatting并不总是会受到惩罚,但确定它的效率并不总是显而易见(或容易).你的琐碎例子实际上和写作一样有效A[16,45,6,40,3] = 100
.你可以通过比较看到这一点
function f(A)
tup = (16,45,6,40,3)
A[tup...] = 100
A
end
function g(A)
A[16,45,6,40,3] = 100
A
end
julia> code_llvm(f, Tuple{Array{Int, 5}})
# Lots of output (bounds checks).
julia> code_llvm(g, Tuple{Array{Int, 5}})
# Identical to above
Run Code Online (Sandbox Code Playgroud)
如果有一个泼溅惩罚,你会以分配的形式看到它.您可以使用@allocated
宏来测试这个,或者只是检查code_llvm
一个引用@jl_pgcstack
- 这就是垃圾收集器,这在任何时候都需要分配.请注意,在更复杂的函数中很可能还会导致分配,因此它的存在并不一定意味着存在splatting悲观化.但如果这是一个热循环,你想最小化所有分配,所以它是一个伟大的目标......即使你的问题不是由于splatting.您也应该使用@code_warntype
,因为类型不好的代码肯定会使splats和许多其他操作失望.如果您的元组输入不好,将会发生以下情况:
function h(A)
tup = ntuple(x->x+1, 5) # type inference doesn't know the type or size of this tuple
A[tup...] = 100
A
end
julia> code_warntype(h, Tuple{Array{Int,5}})
# Lots of red flags
Run Code Online (Sandbox Code Playgroud)
所以优化这个splat将高度依赖于你如何构建或获得tup
.