New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial implementation of non-blocking await for 6.d.PREVIEW #1004
Conversation
For now, just a marker role for things that we can `await`. Later, it it will require a method for subscribing a resumption.
Patch by nine++ cherry-picked and updated to build/work on HEAD.
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.
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`.
Avoids some wasteful work as well as fixing a race.
| has Mu $.result; | ||
| has Exception $.cause; | ||
|
|
||
| method already-success(\result) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
|
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 |
So far, when you
awaitin 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.thenand 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 withawait.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
awaitin the case of an already available result not require concurrency control in thePromisecase, which should be a speed-up. Furthermore, there's now an interface for things that wish to participate in theawaitsystem to implement, so while we just use it forPromise,Supply, andChanneltoday, module space will also be able to create their own things that we canawait.Unless you
use v6.d.PREVIEW, nothing changes as of merging this PR. You have to opt in to get this new behavior ofawait. 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 allawaits on thread pool threads. (Andawaitin the mainline, or in a bareThread, will continue to have the same blocking behavior as today, just implemented through the newAwaitableinterface.)