Last time I wrote, the Rakudo on JVM port was passing around 92% of the specification tests that Rakudo on Parrot can. In the last couple of weeks, we’ve continued hunting down and fixing failures. I’m happy to report that we have already passed the 98% mark – well beyond the 95% I was aiming for by the July release! I’m optimistic that we may be able to push that up to 99% in the coming days. Either way, we’re closing in on the goal spectest wise, meaning the focus should soon move to getting tools like Panda working, followed by the module ecosystem. Happily, arnsholt++ has already started working on the NativeCall support that many modules depend on.
One of the reasons for adding a JVM backend is to unblock work on Rakudo’s support for asynchronous, parallel and concurrent programming. With a YAPC::EU talk on these topics looming, and hating to take to the stage without anything to demonstrate, I’ve started working on this area. It’s early days yet, but here is a quick look at what’s already possible.
There is some basic support for doing stuff in threads.
say "Creating a couple of threads..."; my $t1 = Thread.start({ sleep 1; say "Thread 1 done"; }); my $t2 = Thread.start({ sleep 2; say "Thread 2 done"; }); say "Waiting for joins..."; .join for $t1, $t2; say "Joined!";
This does what you’d naturally expect. However, threads are kind of like the assembly language of parallel programming: occasionally you want to work at that level, but usually it’s much better to work in terms of higher level constructs. Thus, while you can do the above, I don’t suggest it. So what’s available at a higher level? Well, so far, promises are.
say "Creating two promises..."; my $a = async { sleep 2; say "omg slept 2"; 27 } my $b = async { sleep 1; say "omg slept 1"; 15 } say "Scheduler has $*SCHEDULER.outstanding() tasks"; say "Waiting for results..."; say $a.result + $b.result;
The async construct evaluates to a Promise object (name subject to change; Future or Task are other options we could steal from other languages). A Promise is an object that represents a piece of ongoing work. It is not backed by a thread of its own; instead, it is scheduled onto a pool of threads that are spun up on demand, up to a limit. Alternatively, a Promise could be backed by some kind of asynchronous I/O. The point is that it doesn’t much matter what the exact nature of the work is, just that there’s a common way to talk about concurrent work and write combinators over them.
When you ask for the result of a Promise and it is not available, you will block until it is available. If the inside of the async block died, then the exception will be thrown at the point the result method is called. There is also a method “then” for chaining on extra work to be done once the promise is either completed or fails due to an exception:
my $a2 = $a.then(-> $res { say "Got $res.result() from promise a" });
This returns another Promise, thus allowing chaining. There is also a sub await that for now just calls the result method for you, on a whole list of promises if you pass them. Here’s an example:
say [+] await dir('docs/announce').map({ async { .IO.lines.elems } });
This creates a Promise per file in the directory that will count the number of lines in the file. Then, await will wait for each of the promises to give a result, handing them back as they come in to the reduction. Note that in the future, this could probably just be:
say [+] hyper dir('docs/announce').map(*.IO.lines.elems)
But we didn’t implement that yet, and when it does happen then it will most likely not work in terms of simply creating a promise per element.
Remember that promises are much lighter than threads! We’re not spinning up dozens of threads to do the work above, just spreading the load over various threads. And yes, the parallel version does run faster on my dual core laptop than the one that isn’t using async/await.
Future plans for promises include combinators to wait for any or all of them, an API for backing them with things other than work in the thread pool, and making await a bit smarter so that it can suspend an ongoing piece of work in the thread pool when it blocks on another promise, thus freeing up that thread for other work.
Of course, all of this is early and experimental; any/all of the above can change yet, and it’s a long, long way from being exercised to the degree that many other parts of Rakudo have been. Expect changes, and expect many more things to land in the coming months; on my list I have asynchronous I/O and an actors module, and I know pmichaud++ has been thinking a bit about how to evolve the list model to support both race and hyper.
Anyway, that’s the latest news. Next time, hopefully there will be yet more spectest progress and some nice sugar for sorear++’s ground work on Java interop, which is what I used to build the threads/promises implementation.
What you called promise we called in parrot task. This is the same as the parrot thread model. The advantage of parrot tasks over java or moarvm tasks is that they scale linearly to the number of CPUs, and do not need to block when writing to shared resources.
Have you got numbers to back up the scaling claim? Given MoarVM isn’t far along enough to even produce such a number, and the JVM has seen much more work on scaling over many cores than Parrot has (due to the sheer difference in available resources), I’m extremely dubious that the claim holds up to scrutiny.
As for the non-blocking, I don’t consider that a task suffering a race condition *agaisnt itself* is an advantage. That’s what the Parrot model’s non-blocking writes can lead to.
It is documented in the bachelor thesis from Stefan Seifert:
http://act.yapc.eu/ye2012/talk/4071
Click to access Hybrid_Threads_for_the_Parrot_VM.pdf
Please note that I am not skilled enough to be able to participate at the discussion but as Rurban seems to want to use the parrot thread model in p2, IMHO it would be a good idea to take some time to calmly discuss about it and see if this thread model really fit perl6 needs.
Great news! Is there github or link to get a build or source? Thanks and keep up the good work.
Monthly compiler releases are in http://rakudo.org/downloads/rakudo/
Join IRC chanel #perl6 on freenode for more information.
What raiph said for the compiler monthlies; the latest has the threads/promises work. And if you want to track the bleeding edge, the git repo is at:
https://github.com/rakudo/rakudo
Is it possible to compile the rakudo on JVM on windows?
Yes, just need Perl 5 and a sufficiently recent JVM.
You need AtivePerl to run the configure-scripts to be exact. But after that it just works out of the box.