为什么移动foor循环进行列表理解会使函数类型不稳定?

时间:2019-06-14 08:42:44

标签: julia list-comprehension type-stability

查看以下功能:

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循环作为列表理解时,fB1fB2都是类型不稳定和缓慢的,而数值结果(显然)保持不变。

那是为什么?

1 个答案:

答案 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