> epoll uses system calls (“slow”) to add or remove descriptor to the set. select does the same thing in userspace. If you have to add and remove many descriptors per iteration which is typical for short-lived connections then select might be more efficient.
I would have estimated that on a select system call the kernel needs to internally attach some kind of event listener for each passed FD and uninstall it before the system call returns. Which means select is interally a sequence of "iterate over all FDs, check if an event is available and if not install listener", "wait at least one event to happen" and finally "uinstall all listeners". While epoll requires only "wait for at least one event to be available and then iterate over the FDs and record all available events". So I would guess that while epoll requires more syscalls for setup it should be a lot more efficient if a FD is polled more than once. With edge triggering most of the registration/unregistration calls can also be avoided.
Or do kernels have special optimizations that make select internally more efficient than I described? Maybe some memoization of former used pollsets?