在Julia中,数组访问的循环很慢

ore*_*uro 0 julia

我在一个有和没有数组访问的循环之间做了如下比较,发现两者之间的性能差异很大:1.463677 [sec] vs 0.086808 [sec].

你能解释一下如何通过数组访问改进我的代码以及为什么会这样吗?

@inline dist2(p, q) = sqrt((p[1]-q[1])^2+(p[2]-q[2])^2)
function rand_gen()
    r2set = Array[]
    for i=1:10000
        r2_add = rand(2, 1)
        push!(r2set, r2_add)
    end
    return r2set
end

function test()
    N = 10000
    r2set = rand_gen()
    a = [1 1]
    b = [2 2]

    @time for i=1:N, j=1:N
        dist2(r2set[i], r2set[j])
    end

    @time for i=1:N, j=1:N
        dist2(a, b)
    end
end
test()
Run Code Online (Sandbox Code Playgroud)

Bog*_*ski 5

r2set有一个具体的类型是这样的(见https://docs.julialang.org/en/latest/manual/performance-tips/#Avoid-containers-with-abstract-type-parameters-1):

@inline dist2(p, q) = sqrt((p[1]-q[1])^2+(p[2]-q[2])^2)
function rand_gen()
    r2set = Matrix{Float64}[]
    for i=1:10000
        r2_add = rand(2, 1)
        push!(r2set, r2_add)
    end
    return r2set
end

function test()
    N = 10000
    r2set = rand_gen()
    a = [1 1]
    b = [2 2]

    @time for i=1:N, j=1:N
        dist2(r2set[i], r2set[j])
    end

    @time for i=1:N, j=1:N
        dist2(a, b)
    end
end
test()
Run Code Online (Sandbox Code Playgroud)

现在测试是:

julia> test()
  0.347000 seconds
  0.147696 seconds
Run Code Online (Sandbox Code Playgroud)

哪个已经好了.

现在如果你真的想要速度使用不可变类型,例如Tuple不是这样的数组:

@inline dist2(p, q) = sqrt((p[1]-q[1])^2+(p[2]-q[2])^2)
function rand_gen()
    r2set = Tuple{Float64,Float64}[]
    for i=1:10000
        r2_add = (rand(), rand())
        push!(r2set, r2_add)
    end
    return r2set
end

function test()
    N = 10000
    r2set = rand_gen()
    a = (1,1)
    b = (2,2)

    s = 0.0
    @time for i=1:N, j=1:N
        @inbounds s += dist2(r2set[i], r2set[j])
    end

    @time for i=1:N, j=1:N
        s += dist2(a, b)
    end
end
test()
Run Code Online (Sandbox Code Playgroud)

你可以比较两种速度:

julia> test()
  0.038901 seconds
  0.039666 seconds

julia> test()
  0.041379 seconds
  0.039910 seconds
Run Code Online (Sandbox Code Playgroud)

请注意,我添加了一个,s因为没有它,Julia通过注意它没有做任何工作来优化循环.

关键是如果将数组存储在数组中,则外部数组保存指向内部数组的指针,而使用不可变类型时,数据直接存储.