First, I have to wonder whether any of this can be legitimately elevated to the level of a "culture." Right now, according to GitHub "insights," tokio-rs has approximately 2.0 regular, every day contributors. And that's the most widely used Rust async runtime. Everything else is likely even more thin.
Second, Tokio has a lot of share because it was early and aggressive in actually delivering usable async documentation and code. I recall, years ago, reading Tokio documentation on how futures worked and grasping these concepts all the way from file descriptors one might epoll() in C, up to the Rust abstractions, and thinking "hell, I could write an executor from first principles based on this." Tokio earned the advocates it has, as oblivious to the real state of things as some of them might be.
I think the real problem is that async Rust is incomplete. As I said elsewhere, async Rust syntax is fine. The implications of async Rust exposed some papercuts in the language that have had to be dealt with since, but the core syntax is fine. I believe that can be attributed to the serious minded attention that the syntax received from people way, waaay up the cognition curve. The part that didn't get enough thought was async runtimes. In an ideal world, one would develop a Rust library that utilizes and/or implements asynchronous calls and transparently, flawlessly run on any correctly implemented runtime alongside any other number of libraries also utilizing and/or implementing async calls.
That is not the case, and the damage that's doing is severe. For every one person, such as myself, that will dare attempt to articulate this pain and, in the process, certainly revealing clear evidence of blatant ignorance, a thousand others just silently gave up.
Yes I think we agree, though I'd quibble about the async syntax; I use it but I have philosophical concerns about it. But I do think tokio is on the whole well implemented. But it is not a good thing for a single runtime to dominate the language like that.
I've at least thought-experimented with what it would take to write my own code agnostic enough that it could run on both e.g. tokio and e.g. monoio etc. and, well, it just can't happen. Even if you find neutral/unbundled implementations of locks, channels, utilities, to depend on instead, you end up stuck at: task spawning, and any kind of I/O. The former, to me, is a glaring absence from the language standard; async should not have gone out the door without support for it.
I can't argue too much on your view of the syntax. I employ the weasel word "fine" because my experience with it is that I have little to no trouble understanding and using async Rust syntax: I can read and write async Rust and conceptually grasp what is likely going on in the runtime. I have to allow that perhaps it isn't sufficient, and maybe even that this is a factor in the runtime problem.
But there are other, non-syntax issues, such as synchronization primitives, IO events, etc. that are clearly underspecified. No maybes about it.
Tokio monoculture is a serious problem.