Julia - CartesianIndices 的表现

unt*_*gam 3 performance benchmarking julia

我正在挖掘源代码,Base.IteratorsMD我确信Base.nextindfor CartesianIndex(in julia/base/multidimensional.jl,请参见此处https://github.com/JuliaLang/julia/blob/55e36cc308b66d3472990a06b2797f9f9154ea0a/base/multidimensional.jl#L142-L150 ) 的实现效率极低:

function Base.nextind(a::AbstractArray{<:Any,N}, i::CartesianIndex{N}) where {N}
    iter = CartesianIndices(axes(a))
    return CartesianIndex(inc(i.I, first(iter).I, last(iter).I))
end
Run Code Online (Sandbox Code Playgroud)

我认为CartesianIndices(...)在每次调用中创建一个新实例必须非常昂贵,因为在我的机器上CartesianIndices(...)通过 REPL调用似乎创建了所有索引。因此,我为替代实现编写了以下基准脚本mynextind

using Base.IteratorsMD

function mynextind(a::AbstractArray{<:Any,N}, i::CartesianIndex{N}) where {N}
    dims = (x.stop for x in axes(a))
    return CartesianIndex(Base.IteratorsMD.inc(i.I, CartesianIndex(ones(Int64, length(dims))...).I, CartesianIndex(dims...).I))
end

function f(func, M)
    c = CartesianIndex(1,1)
    while true
        (c = func(M, c)) == CartesianIndex(size(M)...) && break
    end
end

A = rand(100,100)

@btime f(Base.nextind, A)
@btime f(mynextind, A)
Run Code Online (Sandbox Code Playgroud)

Base.nextind比 快几个数量级(7?s vs 12ms)mynextind。此外,Base.nextind似乎没有进行任何内存分配。现在我试图理解为什么会这样。CartesianIndices实际上是否创建了所有索引?

Jun*_*ian 5

我认为在每次调用中创建 CartesianIndices(...) 的新实例必须非常昂贵,因为在我的机器上通过 REPL 调用 CartesianIndices(...) 似乎创建了所有索引。

这是无效的。

CartesianIndices(...)在 REPL 中打印时,将打印所有元素。但这并不意味着它将创建所有索引。

正如您在CartesianIndices此处结构的源代码中所见:https : //github.com/JuliaLang/julia/blob/64d8ca49122609d1c10c72a96d1711b95346980a/base/multidimensional.jl#L248

当您创建类似 的实例时CartesianIndices(axes(A)),只会存储轴。您看到所有索引都被打印的原因CartesianIndicesAbstractArray. 它也实现了这些getindex方法。因此,当您键入 时CartesianIndices(axes(A)),所有索引都是按需计算的。

您可以在此处查看有关 CartesianIndices 的更多讨论:https : //discourse.julialang.org/t/psa-replacement-of-ind2sub-sub2ind-in-julia-0-7/14666

  • @untergam:我不知道 Julia 语言,但大概是 REPL *打印*结果的事实。即触发对所有惰性评估事物的需求。如果您使用“CartesianIndices”作为 REPL 中较大表达式的一部分,则不会触发成本。 (2认同)
  • @untergam 我认为 REPL 会调用 `show` 或一些类似于打印结构的函数。然后就被触发了。 (2认同)