2017-07-19 34 views
2
@noinline g(x::Int) = x > 2 ? 1 : nothing 
function test(x::Int) 
    a = g(x) 
    if a == nothing 
     f(a) 
     # Do I need f(a::Void) 
    else 
     f(a) 
     # Do I need f(a::Int) 
    end 
end 

@noinline f(x) = 1 
@noinline f(x::Int) = 2 
@noinline f(x::Void) = 3 

我是正確的說法叫f當朱莉婭不知道的x類型的武器類型斷言。所以它會做一個動態調度? (當然,這兩種類型的調度給出正確的結果)我需要的,如果x ==什麼

(Main.f)(a::Union{Int64, Void})::Int64

出於性能方面的原因,我需要標註我的代碼在臂上,這樣,朱莉婭可以調用f時做靜態調度,而不是動態分配?

@code_warntype test(3) 

Variables: 
    #self#::#test 
    x::Int64 
    a::Union{Int64, Void} 
    #temp#@_4::Core.MethodInstance 
    #temp#@_5::Bool 
    #temp#@_6::Core.MethodInstance 
    #temp#@_7::Int64 
    #temp#@_8::Core.MethodInstance 
    #temp#@_9::Int64 

Body: 
    begin 
     a::Union{Int64, Void} = $(Expr(:invoke, MethodInstance for g(::Int64), :(Main.g), :(x))) # line 4: 
     unless (a::Union{Int64, Void} isa Int64)::Bool goto 6 
     #temp#@_4::Core.MethodInstance = MethodInstance for ==(::Int64, ::Void) 
     goto 15 
     6: 
     unless (a::Union{Int64, Void} isa Void)::Bool goto 10 
     #temp#@_4::Core.MethodInstance = MethodInstance for ==(::Void, ::Void) 
     goto 15 
     10: 
     goto 12 
     12: 
     #temp#@_5::Bool = (a::Union{Int64, Void} == Main.nothing)::Bool 
     goto 17 
     15: 
     #temp#@_5::Bool = $(Expr(:invoke, :(#temp#@_4), :(Main.==), :(a), :(Main.nothing))) 
     17: 
     unless #temp#@_5::Bool goto 36 # line 5: 
     unless (a::Union{Int64, Void} isa Int64)::Bool goto 23 
     #temp#@_6::Core.MethodInstance = MethodInstance for f(::Int64) 
     goto 32 
     23: 
     unless (a::Union{Int64, Void} isa Void)::Bool goto 27 
     #temp#@_6::Core.MethodInstance = MethodInstance for f(::Void) 
     goto 32 
     27: 
     goto 29 
     29: 
     #temp#@_7::Int64 = (Main.f)(a::Union{Int64, Void})::Int64 
     goto 34 
     32: 
     #temp#@_7::Int64 = $(Expr(:invoke, :(#temp#@_6), :(Main.f), :(a))) 
     34: 
     return #temp#@_7::Int64 
     36: # line 7: 
     unless (a::Union{Int64, Void} isa Int64)::Bool goto 41 
     #temp#@_8::Core.MethodInstance = MethodInstance for f(::Int64) 
     goto 50 
     41: 
     unless (a::Union{Int64, Void} isa Void)::Bool goto 45 
     #temp#@_8::Core.MethodInstance = MethodInstance for f(::Void) 
     goto 50 
     45: 
     goto 47 
     47: 
     #temp#@_9::Int64 = (Main.f)(a::Union{Int64, Void})::Int64 
     goto 52 
     50: 
     #temp#@_9::Int64 = $(Expr(:invoke, :(#temp#@_8), :(Main.f), :(a))) 
     52: 
     return #temp#@_9::Int64 
    end::Int64 

回答

4

值得一提的是朱莉婭做動態調度的例子是你寫的吧。 Julia 0.6實際上是在這裏嘗試實現的優化。這就是發生在這樣的行:

unless (a::Union{Int64, Void} isa Int64)::Bool goto 23 
    #temp#@_6::Core.MethodInstance = MethodInstance for f(::Int64) 
    goto 32 
    23: 
    unless (a::Union{Int64, Void} isa Void)::Bool goto 27 
    #temp#@_6::Core.MethodInstance = MethodInstance for f(::Void) 
    goto 32 

這是「拆分」聯合和顯式添加分支來獲得確切的方法實例。

雖然你寫的方式,但朱莉婭缺少==優化。在這種情況下,x == nothing只需呼叫x === nothing,但推斷現在不利用該事實。所以你最終與很多嵌套分支。更改==的嚴格===,你會得到你要找的優化:

julia> function test(x::Int) 
      a = g(x) 
      if a === nothing 
       # … same as above 

julia> @code_warntype test(2) 
Variables: 
    #self#::#test 
    x::Int64 
    a::Union{Int64, Void} 

Body: 
    begin 
     a::Union{Int64, Void} = $(Expr(:invoke, MethodInstance for g(::Int64), :(Main.g), :(x))) # line 3: 
     unless (a::Union{Int64, Void} === Main.nothing)::Bool goto 6 # line 4: 
     return 3 
     6: # line 7: 
     return 2 
    end::Int64 

這實際上是比使用類型斷言有效得多。

有趣的是,f方法是所以簡單,儘管@noinline註釋,朱莉婭仍然內聯。使它們比單個文字值更復雜,並且不會內聯。

相關問題