-
Notifications
You must be signed in to change notification settings - Fork 88
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
writing a library that can be reused across many runtimes #45
Comments
@nikomatsakis Though it's not necessarily "zero-cost", I think the "crossterm" crate with async enabled has an okay approach that should be mentioned here. It essentially starts a background thread (the not zero-cost part) that sleeps most of the time, which lets the futures know when they're ready. After the thread has started, I believe the costs are relatively low, and acceptable for most projects. |
@AldaronLau that's great, thanks! Another approach worth citing (though it has limitations) is the I don't know if there are people with real-life experience using the crate to talk about. Some of the pros I can see theoretically are:
Some of the cons I can see are:
|
@nikomatsakis cool, I didn't know about that crate! Now I'm wondering if similar to The docs say it:
which makes me think it's already pretty close to working like |
There have been proposals for a
There has also been discussion about an extension to
Both of these would make writing runtime-agonstic libraries much easier, but there haven't been any conrete proposals that I know of recently. |
Collecting links is good, but I'd like to focus for now on the challenges -- what is difficult now (and what works well now)? I'd like to hold off on exploring solutions because that quickly gets into the nitty gritty. One thing that could be really useful though is to look through for the counterarguments to a global allocator and make sure we spell those out. We want to be describing the constraints and considerations for whatever solution we wind up with. (My personal opinion is that a global allocator may be part of that, but I'm not sure, and we will want to be careful whatever we do that we leave room for services that have multiple runtimes interacting.) |
The story I would like to see for async Rust is not just to be possible to write cross-runtime libraries, but for it to be the easiest, preferred route: if everybody has access to APIs that abstracts away most differences between runtimes, people will have little reason to directly or indirectly depend on There's another, more philosophical reason to dislike special-casing executors in libraries: perhaps the one we will end up using isn't written yet. So even a library like |
For a real-world example - On Fuchsia, we support a single executor and runtime fuchsia_async library. However, in order to more easily share libraries across host and target, we've partially implemented a compatibility layer to fuchsia-async that's built upon async-std. Unfortunately, some of the decisions we made in our API makes it difficult to share across runtimes. The specific problem I ran into was trying to make a portable version of fuchsia_async::net::fuchsia::tcp. One of the APIs to get a stream of accepted sockets is I could probably change fuchsia-async to match async_std's interface, but it looks like tokio's equivalent accept stream takes ownership over the listener with it's |
Hey 👋 , I would love to rewrite it, also including abstractions for other stuff like sockets, if there's interest. It would probably make a good "playground" for testing executor agnostic ideas. However, I was, and still am, stuck on a good design to have an agnostic runtime. Global So I'm open for any suggestions on how to make the User API and design better. |
@Stupremee thanks! I think that brainstorming what such designs might look like is exactly what I hope to do during the "shiny future" period that is coming up. Maybe we can schedule a time to talk about this. |
That sounds good. You can ping me when the time has come. |
Reproducing this comment by @erickt from another issue:
|
We did a writing session on this and came up with an almost complete outline of a story for this. We will likely meet next week to finish this outline and turn it into an actual story. |
Thanks for this topic. Just wanted to add a +1 on the need for guidance and best practices for writing async libs that don't need full I/O, but just some basic functionality. I'm on my 3rd library that just needs:
It just seems a bit more difficult and confusing than it needs to be for this fairly minimal use case. |
FYI: we met again, and finished the outline. @zeenix is working on turning the outline into a full story. |
I think that a major obstacle for writing a runtime agnostic library is that runtimes currently do not have traits that represent them. We do have traits for Futures, and so it seems like all libraries agree about what a Future is. As far as I know runtimes only have a trait for spawning, and from my experience even that trait is not being respected by most libraries. Without a runtime standard, rust async runtimes slowly diverge, introducing their own incompatible async channels and incompatible traits. Hence writing a runtime-agnostic library becomes more and more difficult. Issues with embedding runtimes in librariesI see a few issues with the current way things work:
Async in OffsetMy main experience with async was working on Offset, a decentralized protocol (library) One of the things that was a huge productivity improvement for me is the ability to create my own test executor, and use it to do things like having detailed control over the passage of time. Think about how to test a timer that shoots only once in 10 minutes. Instead of writing a test that waits for 10 minutes, I prefer to have some system that simulates the passage of time. Another thing that my test executor provided me with is a fully deterministic execution with my own executor's task management. This kind of fine grained control also allows to detect async deadlocks and reproduce them in a deterministic manner. In the world of opaque inner runtimes, detecting such bugs is virtually impossible. One thing I discovered is that if I chose to use any runtime depended library, it would have infected my whole library, making testing using my test executor impossible. I think that the same is true for the case of having a global executor. How to be a runtime agnostic library?I developed a few async projects recently, some of which are libraries (Offset). All of my libraries are 100% runtime agnostic, and my applications are runtime agnostic up to the code of the main() function. Here are some patterns that are shared between my projects:
For me it is always disheartening to see a good library having a path like When having to use runtime-dependent dependencies, much of my development time is dedicated to doing the acrobatics of integrating the dependency as late as possible in the development (As close as possible to |
The text was updated successfully, but these errors were encountered: