Is it fair to say that async/await is a leaky abstraction?
Over the last few years I've come to terms with Rust async await and I see it's value, but the more I explore outside the humble boundaries of Tokio, the more I'm realizing that something about the state of the async ecosystem seems leaky. The idea of being able to swap out runtimes is a cool idea especially for libraries because you don't know what runtime your downstream consumers are going to use.
But the big problem with this is that basically all I/O is coupled to the runtime. This means that swapping out a runtime requires an top-down rewrite of basically all I/O, replacing all network socket stuff and many synchronization primitives, etc. For libraries what this translates to is re-implementing networking and synchronization primitives as wrappers over each of the supported runtimes (like this). And with a quick search on SourceGraph you find these wrappers all over the place.
Like I said, over the years I've come to terms with how Rust does async and I see the value proposition especially from a systems programming perspective. As I've expressed my frustrations, people have helped me understand that there are just different priorities driving Rust async when compared to other concurrency models out there. I accept that. What I'm feeling is a little bit of frustration with whether the async runtime solution really the best we can do given the fact that it means either (1) all downstream consumers have to use the same runtime as a lib, or (2) I have to write wrappers around every runtime that my downstream consumers might want to use?
Anyways, there's what's floating around in my head. These are good faith questions and I'm hoping for good faith responses to help improve my understanding.