And by cheap I mean cheaper than OS threads. The reactor pattern still adds a lot of CPU overhead to each I/O operation.
What's interesting is that Rust had green threads at one point. They implemented that by making std::io async-capable under the hood. But they didn't like it: too much abstraction cost, and it was preventing to add more native i/o features easily.
So they ditched it and now they are doing exactly the same thing to I/O, just in user space, and without green threads.