How does an event loop give you concurrency with one thread?
Because most of what a server does is wait. The loop keeps a queue of ready callbacks and a set of pending I/O registered with the kernel; when a socket becomes readable, the kernel says so and the loop runs the continuation. One thread can hold ten thousand open connections because at any instant nearly all of them are idle. It buys you nothing at all on CPU work — a tight loop blocks everything, and there is no scheduler to preempt it.
The rule that follows: never do blocking or CPU-heavy work on the loop. Hand it to a thread pool or a separate process.