如果我们跑:
@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表达的讨论时遇到了一些麻烦。
答案 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
没有动态调度和分配。