@oxinabox - thanks for the great Lazy Sequences blog post.
ResumableFunctions is a really cool package but I was curious why it ended up being slower than the Channel implementation for generating primes. I did some benchmarking and it appears that the problem may come from the typing of the internal states - known_primes
and x
.
Expanding the macro, the type of both known_primes
and x
became Any
(where they should have been Array{BigInt,1}
and BigInt
respectively. In additional, the literal big"3"
became an Int
in the generated code. In addition, a::Array{BigInt,1}
and z::BigInt
fields were generated but unused. It’s looking more like a bug to me.
Just sharing
julia> @macroexpand(
@resumable function primes_rf()
known_primes = BigInt[2]
x = big"3"
@yield big"2" # Output the first prime, as we already put int in the list of known primes
while true
for p in known_primes
if p > sqrt(x)
# Must be prime as we have not found any divisor
push!(known_primes, x)
@yield x
break
end
if x % p == 0 # p divides
# not prime
break
end
end
x+=1
end
end
)|> MacroTools.striplines
quote
begin
mutable struct ##824 <: ResumableFunctions.FiniteStateMachineIterator
_state::UInt8
x::Any
a::Array{BigInt,1}
p::Any
_iterstate_1::Any
known_primes::Any
_iterator_1::Any
z::BigInt
function ##824(; )::##824
fsmi = new()
fsmi._state = 0x00
fsmi
end
end
end
function (_fsmi::##824)(_arg::Any=nothing; )::Any
_fsmi._state == 0x00 && $(Expr(:symbolicgoto, Symbol("#159#_STATE_0")))
_fsmi._state == 0x01 && $(Expr(:symbolicgoto, Symbol("#157#_STATE_1")))
_fsmi._state == 0x02 && $(Expr(:symbolicgoto, Symbol("#158#_STATE_2")))
error("@resumable function has stopped!")
$(Expr(:symboliclabel, Symbol("#159#_STATE_0")))
_fsmi._state = 0xff
_arg isa Exception && throw(_arg)
_fsmi.known_primes = BigInt[2]
_fsmi.x = 3
_fsmi._state = 0x01
return 2
$(Expr(:symboliclabel, Symbol("#157#_STATE_1")))
_fsmi._state = 0xff
_arg isa Exception && throw(_arg)
while true
_fsmi._iterator_1 = _fsmi.known_primes
_fsmi._iterstate_1 = start(_fsmi._iterator_1)
while !(done(_fsmi._iterator_1, _fsmi._iterstate_1))
(_fsmi.p, _fsmi._iterstate_1) = next(_fsmi._iterator_1, _fsmi._iterstate_1)
if _fsmi.p > sqrt(_fsmi.x)
push!(_fsmi.known_primes, _fsmi.x)
_fsmi._state = 0x02
return _fsmi.x
$(Expr(:symboliclabel, Symbol("#158#_STATE_2")))
_fsmi._state = 0xff
_arg isa Exception && throw(_arg)
break
end
if _fsmi.x % _fsmi.p == 0
break
end
end
_fsmi.x += 1
end
end
function primes_rf(; )::##824
##824()
end
end