And even forgetting the costs of forking, threads are not necessarily much better anyways. I can easily have a single Go program scheduling literally hundreds of thousands of Goroutines across just a few OS level threads and have no problems whatsoever, and in fact I've done exactly that in production, whereas I would never even dream of doing that with threads.
Node.JS's event loop model also doesn't need to spawn threads per connections.
When I say processes and forking are relatively expensive, I don't mean compared to doing the exact same thing with threads; I mean compared to more modern alternatives, like using an event loop or Goroutines.
Event loops and userland cooperative multitasking like Goroutines predate Linux 2.6 kernel threads. They're not "more modern".
The conclusion to be drawn is "Linux threads are costly", not "Linux processes are cheap".
This and "async is always faster" are two things which are no longer true on modern hardware.
Forking a process on Linux uses the same clone() syscall as creating a thread so forking a small binary takes only tens of microseconds, leaving plenty of time for <1ms total response times.
https://eli.thegreenplace.net/2018/launching-linux-threads-a...