查看以下功能:
function fA1(s::AbstractString, n)
T = getfield(Base, Symbol(s))
x = one(T)
for i in 1:n
x = x+x
end
return x
end
function fA2(s::AbstractString, n)
T = getfield(Base, Symbol(s))
x = one(Float64)
for i in 1:n
x = x+x
end
return x
end
function fB1(s::AbstractString, n)
T = getfield(Base, Symbol(s))
x = one(T)
[x = x+x for i in 1:n]
return x
end
function fB2(s::AbstractString, n)
T = getfield(Base, Symbol(s))
x = one(Float64)
[x = x+x for i in 1:n]
return x
end
fA1
是类型不稳定且速度慢的,fA2
是类型稳定且速度快的。
但是,当我将for
循环作为列表理解时,fB1
和fB2
都是类型不稳定和缓慢的,而数值结果(显然)保持不变。
那是为什么?
答案 0 :(得分:1)
Julia手册here中说明了原因。
重要的是要了解理解会产生新的本地作用域,如Julia手册here所述。
在这种情况下,如果您坚持从理解范围内的外部作用域更新变量(通常不建议这样做,因为这样做通常会使阅读此类代码的人感到困惑),据我所知,您将尽力而为(也许有人可以提出更好的解决方案,但考虑到Julia编译器的当前状态,我认为这不太可能)是使用类型注释:
function fB2(n)
x::Float64 = one(Float64)
[x = x+x for i in 1:n]
return x
end
这不会避免装箱,但应使返回类型可推断,并且性能应显着提高。
将来,Julia编译器很有可能会足够聪明,无需类型注释就可以处理此类代码。
以下是性能比较:
julia> using BenchmarkTools
julia> function f_fast(n)
x::Float64 = one(Float64)
[x = x+x for i in 1:n]
return x
end
f_fast (generic function with 1 method)
julia> function f_slow(n)
x = one(Float64)
[x = x+x for i in 1:n]
return x
end
f_slow (generic function with 1 method)
julia> @benchmark f_fast(1000)
BenchmarkTools.Trial:
memory estimate: 23.63 KiB
allocs estimate: 1004
--------------
minimum time: 4.357 μs (0.00% GC)
median time: 7.257 μs (0.00% GC)
mean time: 10.314 μs (16.54% GC)
maximum time: 5.256 ms (99.86% GC)
--------------
samples: 10000
evals/sample: 7
julia> @benchmark f_slow(1000)
BenchmarkTools.Trial:
memory estimate: 23.66 KiB
allocs estimate: 1005
--------------
minimum time: 17.899 μs (0.00% GC)
median time: 26.300 μs (0.00% GC)
mean time: 34.916 μs (15.56% GC)
maximum time: 36.220 ms (99.91% GC)
--------------
samples: 10000
evals/sample: 1