Skip to content

Instantly share code, notes, and snippets.

@gfldex
Created October 23, 2017 21:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gfldex/4e734902dcbabe3ff1f287ef1676a579 to your computer and use it in GitHub Desktop.
Save gfldex/4e734902dcbabe3ff1f287ef1676a579 to your computer and use it in GitHub Desktop.
# The Perl 6 [Rosattacode](http://rosettacode.org/wiki/Parallel_calculations#Perl_6) for parallel calculations is terribly outdated and missing all the goodies that where added or fixed in the last few weeks. With this post I would like to propose an updated version for Rosettacode. If you believe that I missed something feel free to comment below. Please keep in mind that Rosettacode is for showing off, not for being comprehensive.
use v6.d.PREVIEW;
# Perl 6 provides parallel execution of code via threads. There are low level custructs that start a thread or safely pause exectuion.
my $t1 = Thread.start({ say [+] 1..10_000_000 });
my $t2 = Thread.start({ say [*] 1..10_000 });
$t1.finish;
$t2.finish;
my $l = Lock.new;
$l.lock;
$t1 = Thread.start: { $l.lock; say 'got the lock'; $l.unlock };
sleep 2; $l.unlock;
$t1.finish;
# When processing lists, one can use a highlevel Iterator created by the methods `hyper` and `race`. The latter may return values out of order. Those Iterators will distribute the elements of the list to worker threads that are in turn assigned to OS level threads by Rakudos ThreadPoolScheduler. The while construct will block until the last element is processed.
my @values = 1..100;
sub postfix:<!> (Int $n) { [*] 1..$n }
say [+] @values.hyper.map( -> $i { print '.' if $i %% 100; $i!.chars });
# For `for`-lovers there is the `race for` and `hyper for` keyword for distributing work over threads like their respective methods forms.
race for 1..100 {
say .Str; # There be out of order dragons!
}
my @a = do hyper for 1..100 {
.Int! # Here be thread dragons!
}
say [+] @a;
# Perl 6 sports constructs that follow the reactive programming model. One can spin up many worker threads and use a threadsafe `Channel`s or `Supply`s to move values from one thread to another. A `react`-block can combine those streams of values, process the them and react to conditions like cleaning up after a worker thread is done procuding values or dealing with errors. The latter is done by botteling up `Exception`-objects into `Failure`-objects that keep track of where the error first occured and where it was used instread of a proper value.
my \pipe = Supplier::Preserving.new;
start {
for $*HOME {
next if !.IO.r;
pipe.emit: .IO if .f & .ends-with('.txt');
# say „Looking in ⟨{.Str}⟩ for files that end in ".txt"“ if .IO.d;
.IO.dir()».&?BLOCK when .IO.d;
CATCH {
default {
note .^name, ': ', .Str;
pipe.emit: Failure.new(.item);
}
}
}
pipe.done;
}
react {
whenever pipe.Supply {
say „Checking ⟨{.Str}⟩ for "Rosetta".“;
say „I found Rosetta in ⟨{.Str}⟩“ if try .open.slurp.contains('Rosetta');
LAST {
say ‚Done looking for files.‘;
done;
}
CATCH {
default {
note .^name, ': ', .Str;
}
}
}
whenever Promise.in(60*10) {
say „I gave up to find Rosetta after 10 minutes.“;
pipe.done;
done;
}
}
# Many build-in objects will return a `Supply` or a `Promise`. The latter will return a single value or just convey an event like a timeout. In the example above we used a `Primise` in that fashion. Below we shell out to `find` and process its output line by line. This could be used to in a react block if there are many different types of events to process. Here we just `tap` into a stream of values and process them one by one. Since we don't got a `react` block to provide a blocking event loop, we wait for `find` to finish with `await` and process it's exitcode.
my $find = Proc::Async.new('find', $*HOME, '-iname', '*.txt');
$find.stdout.lines.tap: {
say „Looking for "Rosetta" in ⟨$_⟩“;
say „Found "Rosetta" in ⟨$_⟩“ if try .open.slurp.contains('Rosetta');
};
await $find.start.then: {
say „find finished with exitcode: “, .result.exitcode;
};
# Having operators process values in parallel via threads or vector units is yet to be done. Both hyper operators and `Junction`s are candidates for autothreading. If you use them today please keep in mind side effects may provide food guns in the future.
@thundergnat
Copy link

Typos: that where added -> that were added, custructs -> constructs, exectuion -> execution, methods forms -> method forms, build-in -> built-in, Primise -> Promise, we don’t got -> we haven’t got|we don’t have

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment