Does Perl 6 have a fast parallel for loop?

Given some code that does a bit of math / casting for each number from 1 to 500000, we have options:

  • Simple for the loop: for ^500000 -> $i { my $result = ($i ** 2).Str; } for ^500000 -> $i { my $result = ($i ** 2).Str; } . In my unscientific test, it takes 2.8 seconds.

  • The most canonical parallel version does every bit of work in Promise , and then waits for the result. await do for ^500000 -> $i { start { my $result = ($i ** 2).Str; } } await do for ^500000 -> $i { start { my $result = ($i ** 2).Str; } } takes 19 seconds. It is slow! Creating a new promise must have too much overhead to be useful for such a simple calculation.

  • Using the parallel map operation is pretty fast. In 2.0 seconds, the operation seems slow enough to take advantage of the parallelization: (^500000).race.map: -> $i { my $result = ($i ** 2).Str; } (^500000).race.map: -> $i { my $result = ($i ** 2).Str; }

The third option seems to be the best. Unfortunately, it reads like a hack. We should not write map code to iterate in the context of the receiver, because others who read the β€œmap” in the source may suggest that the goal is to create a list that is not our intention. This is a bad message to use map in this way.

Is there any canonical quick way to use Perl 6 built into concurrency? A hyper operator would be ideal if it could take a block instead of functions:

 (^500000)Β».(-> $i { my $result = ($i ** 2).Str; }) # No such method 'CALL-ME' for invocant of type 'Int' 
+5
source share
2 answers

If you want to use a hyper or racing operation, you must write it hyper for @blah.hyper(:batch(10_000)) or race for @blah.race(:batch(10_000)) . Or without parameters: hyper for @blah , race for @blah .

This was resolved because you might have code like for some-operation() { some-non-threadsafe-code } , where some-operation is part of a library or something else. Now you can’t say more if the for loop may contain unsafe code or not, and even if you know that the library does not return HyperSeq at this point in time, that if the author of the library comes up with this great idea to make some-operation faster, if you run it?

This requires that meaning "safely run this loop for the loop" is necessary right where the code is, and not just where the sequence is created.

+6
source

On my PC, this is slightly (~ 15%) faster than a naive loop:

 (^500_000).hyper(batch => 100_000).map(-> $i { my $result = ($i ** 2).Str; }) 

Since the calculation inside the loop is really fast, usually the cost of parallelization and synchronization overshadows any winnings you get from it. The only way is a large batch size.

Update: with a batch size of 200_000 I get slightly better results (several percent faster).

+3
source

Source: https://habr.com/ru/post/1273379/


All Articles