I've explored this subject on my blog, including possible solutions to the problem with these APIs:
https://without.boats/blog/futures-unordered/
https://without.boats/blog/poll-progress/
https://without.boats/blog/the-scoped-task-trilemma/
Also, the rendering and visualization aspect of this is very cool!
Due to the work of you and others I do have hope it will all be better in future.
That said, might be my low standards due to many scars from my c++ background, but I’m already plenty happy with what we have today, so the fact that it will get even better in the next years is like cherry on the cake for me.
For example, do you think it’s better to write “async fn” (call this the high level api) and make them fairly small and contained or is it better to impl Future and use enum Poll for low level control of higher level abstract computations (I.e. the one and only point of Async is “Pending”)?
(Hopefully I made sense) — high level API on low level components, or low level API on high level components, or something else?
is a future a structure or a function or both (trajectory?)
I find the difference between concurrency and parallelism is too subtle to be really satisfyingly / obviously accurate or useful. Might there be a better way to separate or rename these concepts to better convey how they are different?
There are more questions, I wonder if you can show us how to write runtime agnostic async code today (admitting the ecosystem has holes, and setting aside how to solve every problem with async rust, how do we practitioners right now future proof our async code to avoid getting overfit / stuck on the details of the Tokio runtime?)
Sry for long comment, no worries if you’re busy, just ideas for questions to optionally write about
You would almost never implement a future unless you needed that specific future for a purpose
> is a future a structure or a function or both (trajectory?)
It is a structure that implements certain traits.
> I find the difference between concurrency and parallelism is too subtle to be really satisfyingly / obviously accurate or useful. Might there be a better way to separate or rename these concepts to better convey how they are different?
The difference between concurrency and paralellism is way bigger than rust. I'd suggest just learning the concept.
> There are more questions, I wonder if you can show us how to write runtime agnostic async code today (admitting the ecosystem has holes, and setting aside how to solve every problem with async rust, how do we practitioners right now future proof our async code to avoid getting overfit / stuck on the details of the Tokio runtime?)
There is no runtime agnostic way to write things in rust because the runtim handlers are different. When a future can be make progress, the runtime needs to handle there internals. This means that crates are typically written using the core structures of a single runtime. The only thing that is "guaranteed" in rust is what a Future "can do" and the async/await interface.
As for changing runtimes, if you don't know enough to discern between runtimes, you should just use Tokio. It's the standard. You wont need to change.
stream::iter(0..10)
.map(async_work)
.map(|t| spawn(t))
.buffered(3 - 1) // The line above act as a buffered slot
.map(unwrap_join)
.filter_map(async_predicate);
This post was also helpful to understand the issue: https://tmandry.gitlab.io/blog/posts/for-await-buffered-stre...
spawn (in the major executors at least) behaves as though it spawns a new thread to poll on. Therefore work does get underway even if callsite poll is never called, and the callsite only checks the status of the thread/task.
[1] https://github.com/yoshuawuyts/futures-concurrency/releases/...