I still think this is one area Rust missed the mark. Go concurrency is quite amazing. Its fast and easy to reason about. Every language can learn something by how goroutines work here. Most importantly, it feels like you're just interacting with synchronous code. There is no "what color is your function?"[0] problem.
The fundamental primitives Rust decided to adopt are just not ergonomic by comparison, and suffers from the aforementioned "What Color Is Your Function?" problem.
An otherwise great language decided to adopt an old hand grenade in regards to async primitives
This is an absolutely reasonable take. The thing is, this is just a divergence in values. Rust isn’t willing to accept the overheads of that style of concurrency, and is willing to trade off on the “harder to learn but with less overhead” side of this spectrum.
There's an interesting dynamic around asynchronous code in that the way to do it the fastest is to have stackless coroutines which operate on state objects on a batched fashion. This limits what you can do, but completely eliminates a lot of the overheads that are associated with async.
The inclusion of generic async semantics at the language layer is itself a compromise. Rust may have gone a little too far down the "reduce overheads" rabbit hole given that this is the case. Go definitely didn't go far enough for high-performance use cases.
The fundamental primitives Rust decided to adopt are just not ergonomic by comparison, and suffers from the aforementioned "What Color Is Your Function?" problem.
An otherwise great language decided to adopt an old hand grenade in regards to async primitives
[0]: https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...