EventMachine requires fundamental changes to your code.
threads do not.
And even with MRI, you are, I am going to predict, see _significant_ performance improvement using an app server that can dispatch multi-threaded (say, puma) with config.threadsafe!.
I am confused why threads aren't getting more attention on this topic.
I think it's because of the "threads are hard" meme. I think the Ruby community is growing beyond that, but it's not a fast process.
I'm a bit astounded that heroku, in their attempt to deal with, um, let's call it "routing-gate", aren't talking about talking about multi-threaded dispatch and config.threadsafe!, but only unicorn with 2-4 forked processes. When it seems awfully likely that multi-threaded dispatch is going to scale a lot more efficiently with regard to number of overlapping requests.
I think some of it is the lack of mature, robust, 'self-managing' app server solutions. For MRI (with the GIL), what's likely needed is something that can fork multiple processes (to use all cores), with each of those processes dispatching multi-threaded (to deal with I/O blocking as well as even-ing out latency when not all requests finish in identical time). So far as I know, Passenger 4 Enterprise is the only thing that can do this for you, without you having to manually set it all up.