Being lazy on this side of the Channel
While writing Concurrent::File::Find I started with a non-concurrent, lazy gather/take version that was, after working mostly correct, turned into a concurrent, Channel sporting version. This looked very nice and regular. A while ago I bragged about another nice and regular lazy program. With four lazy lists in a row it would be lovely to turn them all into Channels.
Simplified it looks like this:
my \l1 := gather for 1..10 { take .item }; my \l2 := gather for l1 { take .item * 2 }; .say for l2;
We loop over l1
to generate l2
. Now we need to add a Channel, loop over the lazy lists and .send
each value one-by-one, close the Channel for sure and mixin the role to be able to close the Channel from the outside. While we are on it, only create Channels when Rakudo is told to use more then one thread to avoid the overhead of heaving a Channel in the mix.
my &channelify = %*ENV<RAKUDO_MAX_THREADS>:!exists || %*ENV<RAKUDO_MAX_THREADS>.Int <= 1 ?? -> \c { c } !! -> \list, $channel = Channel.new { start { for list { $channel.send($_) } LEAVE $channel.close unless $channel.closed; } $channel.list but role :: { method channel { $channel } } };
my \l1 := channelify gather for 1..10 { take .item }; my \l2 := channelify gather for l1 { take .item * 2 }; .say for l2;
The method check script went from 0m2.978s down to 0m2.555s with a fair bit of Rakudo startup time in the mix. Not bad for some quick copypasta.
It pays to be lazy early on.
UPDATE: I improved on checking the environment variable. At some point in the future Rakudo will sport a sane default. It’s hardcoded to 16 worker threads, IIRC.
-
October 3, 2016 at 23:532016.40 Pull up to the Hacktoberfest | Weekly changes in and around Perl 6