喷溅并不总是会受到惩罚,但确定喷溅的效率并不总是显而易见(或容易)。您的简单示例实际上与编写 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
如果有喷溅处罚,您会以分配的形式看到它。您可以使用@allocated 宏或简单地检查code_llvm 以获取对@jl_pgcstack 的引用来对此进行测试——这就是垃圾收集器,只要有分配就需要它。请注意,在一个更复杂的函数中很可能还有其他事情也会导致分配,因此它的存在并不一定意味着存在喷溅的悲观情绪。但是,如果这是在一个热循环中,您希望最小化所有分配,所以这是一个很好的目标……即使您的问题不是由于飞溅造成的。您还应该使用@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
因此,优化此 splat 将高度依赖于您如何构建或获取 tup。