Initial implementation of non-blocking await for 6.d.PREVIEW #1004

merged 11 commits into from Jan 27, 2017


None yet

3 participants

jnthn commented Jan 25, 2017 edited

So far, when you await in code running on a thread in the thread pool, it would block a real OS thread. This meant that certain patterns had to be expressed in unnatural ways (using .then and a callback), or that the scheduler had to have its maximum number of threads raised really high. For example, sleepsort on a hundred or a thousand values would run into issues there if you wrote it with await.

My original intention for await, when used on a thread pool thread, was that it would instead hand control back to the scheduler so the thread could be used for other work. This would mean we could have thousands of tasks awaiting stuff, and just a handful of threads required for progress.

This PR implements exactly that. As a bonus, it also makes await in the case of an already available result not require concurrency control in the Promise case, which should be a speed-up. Furthermore, there's now an interface for things that wish to participate in the await system to implement, so while we just use it for Promise, Supply, and Channel today, module space will also be able to create their own things that we can await.

Unless you use v6.d.PREVIEW, nothing changes as of merging this PR. You have to opt in to get this new behavior of await. Once Perl 6.d is released, then Rakudo will switch to 6.d being the default and - unless code has explicitly declared itself as wanting 6.c - this will become the default behavior for all awaits on thread pool threads. (And await in the mainline, or in a bare Thread, will continue to have the same blocking behavior as today, just implemented through the new Awaitable interface.)

niner and others added some commits Jan 6, 2016
@niner @jnthn niner First attempt at adding a CORE.d setting
Patch by nine++ cherry-picked and updated to build/work on HEAD.
@jnthn jnthn Stub in the `Awaitable` role.
For now, just a marker role for things that we can `await`. Later, it
it will require a method for subscribing a resumption.
@jnthn jnthn Start sketching out new `await` implementation.
This does not yet support non-blocking `await`, but the factoring is
designed to enable it to be put in place. For now, only Promise has
been updated to support `await` under the new factoring, and only a
single result may be `await`ed.
@jnthn jnthn Initial blocking `await-all` implementation. 7d1f409
@jnthn jnthn Implement get-await-handle for Supply. 6fa4f9d
@jnthn jnthn Don't generate an unrequired accessor. 4d8c32a
@jnthn jnthn Implement get-await-handle for Channel. 0bb2dbc
@jnthn jnthn Implement ThreadPoolScheduler non-blocking await.
Now, if we do an `await` in code being run in the thread pool, and the
awaited value(s) are not yet available, we take a continuation. This
frees up the thread to process more work from the thread pool. When
all of the awaited results are available, or the production of one of
them produces an exception, then the resumption of the continuation
will be scheduled in the thread pool.

This behavior will only happen if you say `use v6.d.PREVIEW`.
@jnthn jnthn Fix thinko in Promise.get-await-handle. 658958e
@jnthn jnthn Fix await-all: $remaining shouldn't go negative.
Avoids some wasteful work as well as fixing a race.
@jnthn jnthn Run S17-supply/nonblocking-await.t.
+ has Mu $.result;
+ has Exception $.cause;
+ method already-success(\result) {
jonathanstowe Jan 25, 2017 Contributor

Strangely I was thinking about this the other day, there seems to be a pattern in Scala where a method that returns a Future may return a Future.failed directly rather than throwing an exception.

jnthn Jan 25, 2017 Contributor

I've been considering Promise.kept(value) and Promise.broken(exception) Promise factories that would cheaply create such Promise objects. Ran into a few situations in my own code where I missed them.


For myself I am very excited by this, there is a fair amount of work-around in Tinky to stop it being impacted awaiting on lots of validators.

jnthn commented Jan 27, 2017

Feedback has been positive, and nobody has registered any objections, so I'll go ahead and merge this. It's low risk for existing code anyway, since you have to write use v6.d.PREVIEW to get the changed functionality.

@jnthn jnthn merged commit dd1cb5f into nom Jan 27, 2017

1 of 2 checks passed

continuous-integration/appveyor/pr AppVeyor build failed
continuous-integration/travis-ci/pr The Travis CI build passed
@jnthn jnthn deleted the nonblocking-await branch Jan 27, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment