使用数组访问的循环在Julia中速度较慢
我对具有和不具有阵列访问的循环进行了如下比较,发现两者之间的性能差异很大:1.463677[秒]与0.086808[秒] 你能解释一下如何通过数组访问来改进我的代码,以及为什么会发生这种情况吗使用数组访问的循环在Julia中速度较慢,julia,Julia,我对具有和不具有阵列访问的循环进行了如下比较,发现两者之间的性能差异很大:1.463677[秒]与0.086808[秒] 你能解释一下如何通过数组访问来改进我的代码,以及为什么会发生这种情况吗 @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) pus
@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()
使
r2set
具有如下具体类型(另请参见):
现在的测试是:
julia> test()
0.347000 seconds
0.147696 seconds
这已经更好了
现在,如果您确实想要速度,请使用不可变类型,例如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()
您将看到两者的速度相当:
julia> test()
0.038901 seconds
0.039666 seconds
julia> test()
0.041379 seconds
0.039910 seconds
注意,我添加了一个s
,因为如果没有它,Julia会通过注意到它不起任何作用来优化循环
关键在于,如果将数组存储在数组中,那么外部数组将保存指向内部数组的指针,而对于不可变类型,数据将直接存储。Make
r2set
具有如下具体类型(另请参见):
现在的测试是:
julia> test()
0.347000 seconds
0.147696 seconds
这已经更好了
现在,如果您确实想要速度,请使用不可变类型,例如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()
您将看到两者的速度相当:
julia> test()
0.038901 seconds
0.039666 seconds
julia> test()
0.041379 seconds
0.039910 seconds
注意,我添加了一个s
,因为如果没有它,Julia会通过注意到它不起任何作用来优化循环
关键是,如果您将数组存储在数组中,那么外部数组将保留指向内部数组的指针,而不可变类型的数据将直接存储。更改
r2set
以具有具体类型的元素r2set=Matrix{Float64}[]
@BogumiłKamiński你的意思是通过r2set=rand>生成r2set
(Float64,N,2)
并通过r2set[i,:]
和r2set[j,:]
访问它?我刚刚做了,花了5.705秒,这更糟糕。我猜切片会在Julia中严重恶化性能……我会给出完整的答案来解释。更改r2set
以具有具体类型的元素r2set=Matrix{Float64}[]
@BogumiłKamiński你是说通过r2set=rand(Float64,N,2)
生成r2set
并通过r2set[i,:]和r2set[j,:]
访问它吗?我刚刚做了,花了5.705[秒],这更糟。我想切片会严重影响Julia的性能……我会给出一个完整的答案来解释。你知道有哪些元组库支持基本操作,比如元组的+*sqrt吗?你的意思是这样的:x,y=(1,2)、(3,4)
。然后你可以做x.+y
,x.*y
,sqrt。(x)
等。没有任何库。是的,我是认真的。实际上,在发布了那个问题后,我发现了一个库(?)命名,这有助于使用不可变向量,我想它可以按照您在回答中的建议使用。是的-StaticArrays.jl是一个非常好的库。请注意,如果数组不像其文档中解释的那样过大,那么它将非常有用。您知道有任何Tuple库支持基本操作,例如Tuple的+*sqrt吗?您的意思是类似这样:x,y=(1,2)、(3,4)
。然后你可以做x.+y
,x.*y
,sqrt.(x)
等等。没有任何库。是的,我是认真的。实际上,在发布了那个问题之后,我发现了一个库(?)命名,这有助于使用不可变向量,我想它可以按照您在回答中的建议使用。是的-StaticArrays.jl是一个非常好的库。请注意,如果数组不像文档中解释的那样过大,那么它将非常有用。