I was experimenting with Julia’s coroutines to do some simple discrete event simulations.
I noticed that consume
returns a type Any
, as shown below. Performance could be much better if the returned type was known. Is there a way to do that?
function prtsk(tsk)
for i=1:10
u=consume(tsk)
println(u)
end
end
function yt()
for i=1:10
produce(i)
end
end
ytt=Task(yt)
julia> prtsk(ytt)
1
2
3
4
5
6
7
8
9
10
julia> @code_warntype prtsk(ytt)
Variables:
#self#::#prtsk
tsk::Task
#temp#::Int64
i::Int64
u::Any
Body:
begin
SSAValue(2) = (Base.select_value)((Base.sle_int)(1,10)::Bool,10,(Base.box)(Int64,(Base.sub_int)(1,1)))::Int64
#temp#::Int64 = 1
3:
unless (Base.box)(Base.Bool,(Base.not_int)((#temp#::Int64 === (Base.box)(Int64,(Base.add_int)(SSAValue(2),1)))::Bool)) goto 15
SSAValue(3) = #temp#::Int64
SSAValue(4) = (Base.box)(Int64,(Base.add_int)(#temp#::Int64,1))
i::Int64 = SSAValue(3)
#temp#::Int64 = SSAValue(4) # line 3:
u::Any = $(Expr(:invoke, LambdaInfo for consume(::Task), :(Main.consume), :(tsk))) # line 4:
(Main.println)(u::Any)::Void
13:
goto 3
15:
return
end::Void
At a guess (untested), ytt is an object defined at global scope. Try putting it inside a function.
ytt
being a global doesn’t matter since it’s not used in the function. Type inference cannot see the control flow of coroutine so it can’t infer the return type of consume. You can add a type assert on it.
After some digging, I learned that the produce/consume approach is deprecated in 0.6. The current documentation is quite sparse, however.
The help documentation makes it clear that a Channel
type could be specified
I tried this new mechanism on 0.6.0-pre.alpha.231, but with little success
julia> function prtsk(c::Channel{Int})
for i=1:10
u=take!(c)
println(u)
end
end
prtsk (generic function with 1 method)
julia> function yt(c::Channel)
for i=1:10
put!(c,i)
end
end
yt (generic function with 1 method)
julia> chnl=Channel(yt,ctype=Int)
Channel{Int64}(sz_max:0,sz_curr:1)
julia> @code_warntype prtsk(chnl)
Variables:
#self#::#prtsk
c::Channel{Int64}
i::Int64
u::Any
#temp#::Int64
Body:
begin
SSAValue(2) = (Base.select_value)((Base.sle_int)(1, 10)::Bool, 10, (Base.sub_int)(1, 1)::Int64)::Int64
#temp#::Int64 = 1
3:
unless (Base.not_int)((#temp#::Int64 === (Base.add_int)(SSAValue(2), 1)::Int64)::Bool)::Bool goto 14
SSAValue(3) = #temp#::Int64
SSAValue(4) = (Base.add_int)(#temp#::Int64, 1)::Int64
#temp#::Int64 = SSAValue(4) # line 3:
u::Any = $(Expr(:invoke, MethodInstance for take!(::Channel{Int64}), :(Main.take!), :(c))) # line 4:
(Main.println)(u::Any)::Void
12:
goto 3
14:
return
end::Void
Not sure if this is by design, or would it warrant an issue.
Interestingly, if I use a slight different mechanism for Channel generation, I get slight better generated code.
julia> function yt()
c=Channel{Int}(10)
@async begin
for i=1:10
put!(c,i)
end
close(c)
end
c
end
yt (generic function with 2 methods)
julia> chnl=yt()
Channel{Int64}(sz_max:10,sz_curr:10)
julia> @code_warntype prtsk(chnl)
Variables:
#self#::#prtsk
c::Channel{Int64}
i::Int64
u::Int64
#temp#::Int64
Body:
begin
SSAValue(4) = (Base.select_value)((Base.sle_int)(1, 10)::Bool, 10, (Base.sub_int)(1, 1)::Int64)::Int64
#temp#::Int64 = 1
3:
unless (Base.not_int)((#temp#::Int64 === (Base.add_int)(SSAValue(4), 1)::Int64)::Bool)::Bool goto 20
SSAValue(5) = #temp#::Int64
SSAValue(6) = (Base.add_int)(#temp#::Int64, 1)::Int64
#temp#::Int64 = SSAValue(6) # line 3:
SSAValue(2) = $(Expr(:invoke, MethodInstance for take!(::Channel{Int64}), :(Main.take!), :(c)))
u::Int64 = (Core.typeassert)((Base.convert)(Main.Int, SSAValue(2))::Any, Main.Int)::Int64 # line 4:
$(Expr(:inbounds, false))
# meta: location coreio.jl println 5
SSAValue(3) = (Core.typeassert)(Base.STDOUT, Base.IO)::IO
# meta: pop location
$(Expr(:inbounds, :pop))
(Base.print)(SSAValue(3), u::Int64, $(QuoteNode('\n')))::Void
18:
goto 3
20:
return
end::Void
So in this version u
is of type Int32
at the outset.
I can’t reproduce your issue. The @code_warntype
is free of type instabilities for me (except, of course, STDOUT
).
Perhaps try updating to the latest beta?
@fengyang.wang, I concur. In 0.6.0-pre.beta.146, I do not see any type instabilities.
1 Like