The job of multiplexing
With non blocking sockets you still need to know which connections have data. IO multiplexing is a kernel service that lets one thread hand in a set of file descriptors and block until at least one of them is ready. This is how an event loop watches many sockets with a single thread.
select and poll
select takes three bitmaps of descriptors and a timeout. It is simple but limited by a fixed FD_SETSIZE and it must scan every descriptor on each call. poll replaces the bitmaps with an array of structures, removing the size cap, but it still passes the whole list every call and scans all of it. Both are linear in the number of watched descriptors.
epoll
epoll on Linux fixes the scaling problem. You register descriptors once into a kernel data structure, then call epoll wait to receive only the ones that became ready. Cost scales with the number of active connections, not the total watched, which is decisive when most of ten thousand connections are idle.
- select and poll rescan the full set each call, so cost grows with total descriptors
- epoll registers once and returns only ready events, scaling with activity
Key idea
select and poll scan every watched descriptor each call, while epoll registers them once and returns only the ones that are ready.