Earlier quoted context omitted.
It was news to me that Rails operated in this way. It is a very weak concurrency model (to be precise: it is nonexistent ). I knew that Rails was naive, but I had not dawned on me just how naive it is. It is interesting because then a system like node.js is a giant leap in the right direction - even if there are better languages out there. ( disclaimer: I do Erlang for a living and often operate in highly concurrent…
Rails has a pure shared-nothing scale-out philosophy; it achieves concurrency with multiple processes. The fact that Heroku only runs one process per dyno by default is a shame though.
Context switches are expensive. Very expensive. So your system runs overhead in the operating system. And you need to spawn a process per request.
Pooling processes is a problem as well. If we only have 4 workers in the pool, then we have to queue requests on one of the 4 workers. But we don't know how expensive those requests are to serve, a priori. Even knowing the queue length or the queue sojourn time won't be able to divulge this information to us, only help a little. More workers just push the problem out further.
If you want to be fast, you need:
The ability to switch between work quickly, in the same process.
The ability to interleave expensive work with cheap work.
The two main solutions are evented servers: Node.js, Twisted, Tornado (both python); and preemptive runtimes: Go, Haskell, Erlang (of which Erlang is the only truly preemptive). I much prefer the preempted solution because it is automatic and you don't have to code anything yourself.
There is a strong similarity to cooperative and preemptive multitasking in operating systems by the way. Events are cooperative. Do note there are no more cooperative operating systems around which you use on a daily basis :)