Skip to main content

Why Epoll is 100x Faster Than Select (I/O Multiplexing)

🎯 The Question​

"How do high-performance servers (NGINX, Redis, Node.js) handle 100,000 concurrent client connections on a single thread? Why is Linux epoll 100Γ—100\times faster than traditional select() and poll()?"


⚑ 30-Second Elevator Pitch​

When a single server thread manages 10,000 socket connections, usually only 10 of those sockets have active incoming data at any given millisecond.

  • With select() / poll() (O(N)O(N) Complexity):
    1. The application must copy an array of all 10,000 socket file descriptors from User Space to Kernel Space on every single poll cycle.
    2. The kernel iterates through all 10,000 sockets one-by-one to check readiness.
    3. The application must scan all 10,000 sockets again to find the 10 ready ones.
  • With epoll (O(1)O(1) Event-Driven):
    1. File descriptors are registered once in a kernel-maintained Red-Black Tree.
    2. When a network packet arrives, the network card interrupt puts that socket directly into an epoll Ready List (Doubly Linked List).
    3. epoll_wait() returns only the 10 ready sockets in O(1)O(1) time.

🧠 Under-the-Hood: Linear Polling vs. Kernel Event Callback​


πŸ”¬ The 3 System Calls of epoll​

  1. epoll_create1(): Creates the epoll kernel context instance.
  2. epoll_ctl(): Adds, modifies, or deletes monitored file descriptors in the kernel's Red-Black Tree (O(log⁑N)O(\log N) one-time setup).
  3. epoll_wait(): Suspends the thread until events occur, returning only the ready file descriptors in O(1)O(1) time.

πŸ“Œ Comparison Matrix: select vs. poll vs. epoll​

Metricselect()poll()epoll()
Time ComplexityO(N)O(N)O(N)O(N)⚑ O(1)O(1) (Proportional to active events)
Max Descriptor Limit1024 (FD_SETSIZE)Unlimited (Array)Unlimited (Kernel memory)
Kernel Data CopyCopies entire array every callCopies entire array every call⚑ Zero copy (Registered once)
Kernel Search MechanismLinear loop through all FDsLinear loop through all FDsHardware interrupt callback to Ready List
Trigger ModesLevel Triggered onlyLevel Triggered onlyLevel Triggered & Edge Triggered

πŸ’‘ What Interviewers Ask Next (Follow-Up Traps)​

  1. "What is the difference between Level-Triggered (LT) and Edge-Triggered (ET) in epoll?"

    • Answer: Level-Triggered (Default) continuously notifies you as long as unread data remains in the socket buffer. Edge-Triggered (High Performance) notifies you only when new data arrives. In ET mode, the application must read using a non-blocking loop until EAGAIN / EWOULDBLOCK is returned, otherwise remaining data will stall.
  2. "What is the equivalent of epoll on macOS/BSD and Windows?"

    • Answer: macOS/BSD uses kqueue, which operates on a similar event-driven design. Windows uses IOCP (I/O Completion Ports), which uses an asynchronous completion notification model rather than readiness notification.

Placement & Interview Takeaway

Interview Answer: select degrades linearly (O(N)O(N)) because it repeatedly copies and scans the entire list of monitored sockets. epoll operates in O(1)O(1) time by storing sockets in a kernel red-black tree and using hardware interrupt callbacks to deliver only active, ready file descriptors to the application.


πŸ“Ί Video Explanation​

πŸš€ Level Up Your Engineering Mindset

Never Study in Isolation. Join Binary Dose.

Connect with fellow engineers, clear conceptual doubts, and get 2 visual breakdowns & engineering mental models daily across our community channels.

Discord
Official Hub

Discord Community

Start at #welcome-and-rules, say hello in #general-chat, clear doubts, and collaborate with engineers worldwide.

Join Discord Server→
⚑
Daily Knowledge Drops

Daily Visual Deep-Dives

Bite-sized system design schematics, core OS internals, and DSA intuition served right into your feeds every single day.

πŸ’‘Have handwritten notes, cheat-sheets, or want to publish a technical article?
Learn How to Contribute→