Spawnratelimiting
IRC keeps insisting on being a good source of thought. A few days ago rcmlz wished to parallelise quicksort. Raku doesn’t sport a facility to make recursion “just work” with oodles of cores. Quicksort is a little special in that regard, as it has a double tail-call.
quicksort(@before), $pivot, quicksort(@after)
Just wrapping the two calls into start
-block will spawn way to many threads. Ergo, I need a function that takes another function and it’s arguments and limits the use of start
-blocks.
my atomicint $spawn-limit = 8;
sub spawn(&c, |args) {
# dd ⚛$spawn-limit;
⚛$spawn-limit > 0
?? ($spawn-limit⚛-- ;start { LEAVE $spawn-limit⚛++; c(|args) })
!! c(|args)
}
This Routine will either return whatever c
returns or a Promise
. I need a way to convert the latter to values.
sub collect(*@things) {
slip @things.map: -> $thing { $thing ~~ Promise ?? await $thing !! $thing }
}
Now I can change quicksort
without getting into trouble with oversharing objects.
multi quicksort([]) { () }
multi quicksort([$pivot, *@rest]) {
my @before = @rest.grep(* before $pivot);
my @after = @rest.grep(* !before $pivot);
flat collect spawn(&?ROUTINE.dispatcher, @before), $pivot, spawn(&?ROUTINE.dispatcher, @after)
}
my @a = ('a'..'z').roll(12).join xx 2**16;
say quicksort @a;
# OUTPUT:
# Flattened array has 65536 elements, but argument lists are limited to 65535
# in sub quicksort at tmp/2021-03-08.raku line 2601
# in block <unit> at tmp/2021-03-08.raku line 2611
Well, I could if Rakudo would be production ready. This bug is old and awful. Test driven programmers like to program test-driven but don’t fancy to wait for hours to see tests complete. As a result very few test with large datasets. (And 65536
elements is not much these days.) It’s fairly easy to start with a project in production that slowly grows it’s database and eventually fails with a runtime error.
At least for now, destructuring is best done by hand.
-
October 9, 2023 at 21:492023.41 Free In Three – Rakudo Weekly News