Julia 多次从分布中提取的最快方法
这: 比这要快一些:Julia 多次从分布中提取的最快方法,julia,Julia,这: 比这要快一些: function draw1(n) return rand(Normal(0,1), Int(n)) end 只是好奇为什么会这样,以及显式循环方式是否可以加速(我尝试了@inbounds和@simd,但没有得到加速)。这是不是初始分配的zero()?我分别在0.25秒左右计时,这并不能完全解释差异(另外,第一种方法不是在引擎盖下预先分配阵列吗?) 例如: function draw2(n) result = zeros(Float64, Int(n))
function draw1(n)
return rand(Normal(0,1), Int(n))
end
只是好奇为什么会这样,以及显式循环方式是否可以加速(我尝试了@inbounds
和@simd
,但没有得到加速)。这是不是初始分配的zero()
?我分别在0.25秒左右计时,这并不能完全解释差异(另外,第一种方法不是在引擎盖下预先分配阵列吗?)
例如:
function draw2(n)
result = zeros(Float64, Int(n))
for i=1:Int(n)
result[i] = rand(Normal(0,1))
end
return result
end
尝试以下实现:
@time x = draw1(1e08)
1.169986 seconds (6 allocations: 762.940 MiB, 4.53% gc time)
@time y = draw2(1e08)
1.824750 seconds (6 allocations: 762.940 MiB, 3.05% gc time)
区别是什么:
- 使用
@inbounds
- 仅创建一次
Normal(0,1)
- 更快地初始化
结果
draw1
相同(虽然我没有在10e8向量大小上测试它(内存不足)-如果您可以运行这样的@benchmark
,那就太好了):
编辑:实际上在一个单独的函数中定义一个循环(与rand
的做法完全相同)使draw4
的性能比draw3
要好一点:
julia> using BenchmarkTools
julia> @benchmark draw1(10e5)
BenchmarkTools.Trial:
memory estimate: 7.63 MiB
allocs estimate: 2
--------------
minimum time: 12.296 ms (0.00% GC)
median time: 13.012 ms (0.00% GC)
mean time: 14.510 ms (8.49% GC)
maximum time: 84.253 ms (81.30% GC)
--------------
samples: 345
evals/sample: 1
julia> @benchmark draw2(10e5)
BenchmarkTools.Trial:
memory estimate: 7.63 MiB
allocs estimate: 2
--------------
minimum time: 20.374 ms (0.00% GC)
median time: 21.622 ms (0.00% GC)
mean time: 22.787 ms (5.95% GC)
maximum time: 92.265 ms (77.18% GC)
--------------
samples: 220
evals/sample: 1
julia> @benchmark draw3(10e5)
BenchmarkTools.Trial:
memory estimate: 7.63 MiB
allocs estimate: 2
--------------
minimum time: 12.415 ms (0.00% GC)
median time: 12.956 ms (0.00% GC)
mean time: 14.456 ms (8.67% GC)
maximum time: 84.342 ms (83.74% GC)
--------------
samples: 346
evals/sample: 1
尝试以下实现:
@time x = draw1(1e08)
1.169986 seconds (6 allocations: 762.940 MiB, 4.53% gc time)
@time y = draw2(1e08)
1.824750 seconds (6 allocations: 762.940 MiB, 3.05% gc time)
区别是什么:
- 使用
@inbounds
- 仅创建一次
Normal(0,1)
- 更快地初始化
结果
draw1
相同(虽然我没有在10e8向量大小上测试它(内存不足)-如果您可以运行这样的@benchmark
,那就太好了):
编辑:实际上在一个单独的函数中定义一个循环(与rand
的做法完全相同)使draw4
的性能比draw3
要好一点:
julia> using BenchmarkTools
julia> @benchmark draw1(10e5)
BenchmarkTools.Trial:
memory estimate: 7.63 MiB
allocs estimate: 2
--------------
minimum time: 12.296 ms (0.00% GC)
median time: 13.012 ms (0.00% GC)
mean time: 14.510 ms (8.49% GC)
maximum time: 84.253 ms (81.30% GC)
--------------
samples: 345
evals/sample: 1
julia> @benchmark draw2(10e5)
BenchmarkTools.Trial:
memory estimate: 7.63 MiB
allocs estimate: 2
--------------
minimum time: 20.374 ms (0.00% GC)
median time: 21.622 ms (0.00% GC)
mean time: 22.787 ms (5.95% GC)
maximum time: 92.265 ms (77.18% GC)
--------------
samples: 220
evals/sample: 1
julia> @benchmark draw3(10e5)
BenchmarkTools.Trial:
memory estimate: 7.63 MiB
allocs estimate: 2
--------------
minimum time: 12.415 ms (0.00% GC)
median time: 12.956 ms (0.00% GC)
mean time: 14.456 ms (8.67% GC)
maximum time: 84.342 ms (83.74% GC)
--------------
samples: 346
evals/sample: 1
一个简短的答案是,内置实现是最快的,幸运的是,这种情况经常发生 您可以使用内置的
function g!(d, v)
@inbounds for i=1:length(v)
v[i] = rand(d)
end
end
function draw4(n)
result = Vector{Float64}(Int(n))
g!(Normal(0,1), result)
return result
end
用
rand代码>总是在边界内。一个简短的答案是,内置实现速度最快,幸运的是,这种情况经常发生
您可以使用内置的
function g!(d, v)
@inbounds for i=1:length(v)
v[i] = rand(d)
end
end
function draw4(n)
result = Vector{Float64}(Int(n))
g!(Normal(0,1), result)
return result
end
用rand代码>总是在边界内。看看的定义吧!(s::Sampleable{Univariate},A::AbstractArray)
在Distributions包中,您将看到它实际上执行了一个循环。每个人似乎都忽略了randn
,它基本上对这个特定的发行版执行相同的操作draw6(n)=randn(n)
在我的机器上是最快的(但并不显著)看看的定义吧!(s::Sampleable{Univariate},A::AbstractArray)
在Distributions包中,您将看到它实际上执行了一个循环。每个人似乎都忽略了randn
,它基本上对这个特定的发行版执行相同的操作draw6(n)=randn(n)
在我的机器上是最快的(但不显著)