Hi. First thread.
we all know the generator pattern from Python and elsewhere.
def mygenerator():
for i in range(10):
yield i
I know the “proper” way to do this is to write a struct with a method on Base.iterate
, but sometimes you don’t need to / want to implement a struct for something that is more easily described in terms of procedures. I’ve seen the pattern with Channels floating around online, and I know using closures is also a popular strategy for this in other languages. i.e.
function countto(n)
count = 0
() -> (count >= n ? nothing : count += 1)
end
function closuretest()
a_cool_million = countto(1_000_000)
while (i = a_cool_million()) != nothing end
end
function countto2(n)
Channel(ctype=Int) do c
count = 0
while count >= n
put!(c += 1, count)
end
end
end
function channeltest()
for i in countto2(1_000_000) end
end
I like the way the channel version a little more because I like that it automatically provides an interface for for loops and, to my eye, the code is a little easier to with the loop than with the closure.
then I ran the code a few times to see how each would look in terms of performance:
@time closuretest()
@time closuretest()
@time closuretest()
@time closuretest()
println()
@time channeltest()
@time channeltest()
@time channeltest()
@time channeltest()
(did the extra runs to make sure the JIT was warm)
0.064392 seconds (2.01 M allocations: 30.837 MiB)
0.051788 seconds (2.00 M allocations: 30.510 MiB, 3.74% gc time)
0.049927 seconds (2.00 M allocations: 30.510 MiB, 7.13% gc time)
0.046646 seconds (2.00 M allocations: 30.510 MiB, 0.60% gc time)
0.189093 seconds (331.03 k allocations: 16.900 MiB, 1.23% gc time)
0.000072 seconds (31 allocations: 2.266 KiB)
0.000045 seconds (31 allocations: 2.266 KiB)
0.000045 seconds (31 allocations: 2.266 KiB)
So, yeah, wasn’t expecting that. Obviously the channel generator pattern is better from a performance perspective, which I wouldn’t have expected, since it has to hit the scheduler on every iteration (or not?)
Anyway, I don’t put too much stock in the current poor performance of closures, since that can be fixed. I’m mostly just wondering which pattern is considered more idiomatic in Julia.