从@code_warntype解释Body表达式

时间:2016-06-17 03:24:47

标签: julia

如果我们跑:

@code_warntype deepcopy(rand(2))

在Julia REPL中,输出包含Body表达式中的标记值。具体来说,最后两个Any

Body:
  begin  # deepcopy.jl, line 8:
      GenSym(0) = (Base.Array)(Base.Any,32)::Array{Any,1}
      return (Base.deepcopy_internal)(x::Array{Float64,1},$(Expr(:new, :((top(getfield))(Base,:ObjectIdDict)::Type{ObjectIdDict}), GenSym(0))))::Any
  end::Any

我从this question了解到,如果主要关注的是类型不稳定,我们通常不需要担心Body表达式中的标记值。相反,我的问题是:

为什么来自Base的相当简单的函数会在@code_warntype中生成任何标记的值?我确信有充分的理由,但我是新解释@code_warntype的输出,并且在理解官方文档中对Body表达的讨论时遇到了一些麻烦。

1 个答案:

答案 0 :(得分:5)

这是类型推断无法确定函数返回类型的情况的示例。 (注意返回值上的::Any!) 是一个问题,不是因为类型不稳定导致计算本身会变慢,而是因为返回类型无法推断,所以使用返回类型的未来计算将受到类型不稳定的影响。

您可以通过查看以下分配来查看此效果:

julia> function f()
         y = rand(10)
         @time y[1] + y[10]
         z = deepcopy(y)
         @time z[1] + z[10]
       end
f (generic function with 1 method)

julia> f();  # ignore output here on first compile

julia> f();
  0.000000 seconds
  0.000002 seconds (3 allocations: 48 bytes)

请注意,第二个操作需要分配并需要时间,因为涉及拆箱和动态调度。

在当前每晚构建的0.5(可能会在几个月内发布)中,这已经是fixed。因此

julia> @code_warntype deepcopy(rand(2))
Variables:
  #self#::Base.#deepcopy
  x::Array{Float64,1}

Body:
  begin  # deepcopy.jl, line 8:
      # meta: location dict.jl Type # dict.jl, line 338:
      SSAValue(1) = (Core.ccall)(:jl_alloc_array_1d,(Core.apply_type)(Core.Array,Any,1)::Type{Array{Any,1}},(Core.svec)(Core.Any,Core.Int)::SimpleVector,Array{Any,1},0,32,0)::Array{Any,1}
      # meta: pop location
      return (Core.typeassert)((Base.deepcopy_internal)(x::Array{Float64,1},$(Expr(:new, :(Base.ObjectIdDict), SSAValue(1))))::Any,Array{Float64,1})::Array{Float64,1}
  end::Array{Float64,1}

没有类型不稳定,

julia> f()
  0.000000 seconds
  0.000000 seconds

没有动态调度和分配。