With standard library support, green threads can be just fine. I've worked with many, many C programs that were nbio and green threads. Cancellation is trivial when you are writing the scheduler! In these cases, I used multiprocessing when I needed parallelism. The answer to "If you're blocking on a socket recv in a thread..." is to not ever do that; the library should provide a green recv that appears to be blocking to the code, but is implemented with non-blocking calls underneath. With the privilege of being the standard library, there are many ways to enforce this.
N to M is much harder to get cancellation right, but again if you write the scheduler, you can define the cancellation points, so you are not beholden to undefined behavior. Instantly cancelling a thread is just not solvable, and for Rust, which cares about low-level performance &c. then long-running computations could explicitly check for cancellation when it is needed. Threads that perform I/O regularly will naturally hit cancellation points.
Cancellation is a huge problem in concurrency, and the usual answer to "how do I cancel a thread" is "you don't want to cancel a thread" which is rather unsatisfying. As you point out, it's not like using async and/or promises automatically solves the problem either; the only way to get it right is to build it in from the start.
N to M is much harder to get cancellation right, but again if you write the scheduler, you can define the cancellation points, so you are not beholden to undefined behavior. Instantly cancelling a thread is just not solvable, and for Rust, which cares about low-level performance &c. then long-running computations could explicitly check for cancellation when it is needed. Threads that perform I/O regularly will naturally hit cancellation points.
Cancellation is a huge problem in concurrency, and the usual answer to "how do I cancel a thread" is "you don't want to cancel a thread" which is rather unsatisfying. As you point out, it's not like using async and/or promises automatically solves the problem either; the only way to get it right is to build it in from the start.