RFC & WIP - Libuv powered futures #1050
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR is a WIP that introduces Rust future execution managed by libuv with a working implementation.
This allows for Rust code to run concurrently on the main thread without blocking the JavaScript thread.
It's still a work in progress, requesting comments for ways I can improve the implementation if it's a good candidate for contribution.
It might be a bit confusing for consumers given the API might conflict with the tokio runtime - so there's probably a discussion to be had there.
I only actually changed 5 files, the other changes are vendoring inPublished my fork of libuv for Rust to reduce the diff.libuv-rs
to reuse their C bindings. In the future the relevant bindings can be brought over rather than vendoring in the whole crate.Examples
Async Function Declaration
Simple Async
Declare an async function that returns a promise and does not block the main thread.
Async MPSC Channel
This also enables the use of async channels on the main thread
Function Async Closure
You can spawn an async future within a closure using
cx.execute_async(|| async {})
.How does this work? Tokio?
This works by essentially bolting a Rust futures executor onto Nodejs's libuv. It uses libuv hooks to trigger the Rust future executor. The futures executor runs until Rust futures are pending then yields back to nodejs's event loop.
This means that the Rust event loop will never block Nodejs's event loop and vice versa, yet both can drive their tasks forward.
I'm using the lightweight local thread executor from the futures crate.
For channels, sleep, and other common async tasks, utilities from async-std can be used.
Tokio is not suitable for this use case as it's designed to be the only executor running and cannot be driven (or at least I cannot figure out how to drive it) from an external executor.
TODO:
[] Tests
[] Error handing
[] Documentation
[] Missing functionality