To be fair though M:N threads aren't the provenance of research language, Go and Rust both have them, and I'm sure some other languages.
(But it's awesome Java has them now too, other languages getting the feature earlier doesn't really devalue it.)
(But it's awesome Java has them now too, other languages getting the feature earlier doesn't really devalue it.)
Virtual threads mean that a blocking thread can yield to any other non blocking thread seamlessly and with very little overhead. .NET Tasks cannot do this as far as I can tell.
.NET might indeed have a virtual thread abstraction and if it does you could of course implement the Task abstraction on top of either virtual threads or OS threads, but what you linked to is not a proof that it does.
(As a note, cooperative scheduling also requires a runtime - Rust might not "have a runtime" by default but you need to opt into one to use async.)