DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PC×
Skip to content
World desk6 min

Epoll vs. Select vs. Poll: Choosing a Linux API for 100,000 Connections

Epoll’s persistent registrations make it a strong Linux choice for very large, mostly idle descriptor sets—but the API alone cannot guarantee 100,000 connections.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For a Linux server monitoring a very large set of mostly idle connections, epoll is generally the best fit: it keeps watched descriptors registered in the kernel and returns ready events, instead of requiring the application to resubmit the full watched set on every wait. That design can scale better as the watched set grows, but it does not guarantee that a particular machine or application can sustain 100,000 connections.

What changes inside the wait operation?

The key difference is where the watched set lives between waits. With select and poll, the application presents the descriptors and requested events each time it waits. With epoll, the application registers descriptors with an epoll instance and later asks for events that are ready.

As an Amazon Associate I earn from qualifying purchases.

select: resubmit descriptor sets

The application supplies read, write, and exception descriptor sets plus an nfds boundary. The sets are value-result arguments: the call changes them to indicate readiness, so the caller must rebuild or restore them before the next wait. The kernel checks the specified descriptors and returns readiness information for the application to inspect.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

There is also a notable limit in the glibc fd_set interface: FD_SETSIZE is 1,024, so descriptor numbers must be below 1,024 when using that interface. This is not a universal 1,024-descriptor cap imposed by the Linux kernel’s select system call; it is a constraint of the glibc interface. The Linux man-pages project describes the limitation in select(2) and says modern applications should use poll or epoll instead in this context.

poll: resubmit an array

The application passes an array of pollfd records, each identifying a descriptor and the events of interest. Unlike glibc’s fd_set, this interface does not have that fixed 1,024-descriptor-number limit. But the application still supplies the watched array on each wait, and the kernel checks the specified descriptors to determine which are ready.

epoll: keep registrations, retrieve ready events

The application creates an epoll instance, registers or changes watched descriptors with epoll_ctl, and retrieves events with epoll_wait. The kernel maintains an interest list of registered descriptors and a ready list populated as watched descriptors become ready. The application can therefore avoid resubmitting its entire watched set on every wait.

The Linux man-pages project describes epoll as an API that “scales well to large numbers of watched file descriptors.” That is a statement about the API’s suitability for large watched sets, not a promise of a particular connection count or performance result. Michael Kerrisk’s Linux/UNIX system programming slides explain the design distinction: select and poll repeatedly pass the set to be checked, while epoll retains the watched set and makes ready events available. This describes the public interface model; it does not establish a universal complexity formula or benchmark for every kernel and workload.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How do the three APIs compare for a large connection set?

API What the application provides Watched-set behavior Descriptor-number constraint Platform scope
select Read, write, and exception sets plus an nfds boundary Rebuild or restore the value-result sets and pass them again for each wait glibc fd_set has FD_SETSIZE 1,024; descriptor numbers must be below 1,024 Longstanding portable interface
poll An array of pollfd records Pass the watched array again for each wait No equivalent fixed fd_set size limit Longstanding portable interface
epoll Persistent registrations managed with epoll_ctl; ready events retrieved with epoll_wait Kernel retains an interest list and reports ready events No fixed fd_set limit Linux-specific

For a large set in which most connections are idle at any given moment, epoll’s persistent registration model avoids repeatedly presenting and checking the complete set in the same way as select and poll. That is the reason it is usually the suitable Linux choice here. Exact performance still depends on the workload and implementation; the design alone does not establish a fixed speedup.

Does epoll make 100,000 connections possible?

No single readiness API guarantees that capacity. The sources describing these APIs do not establish that a particular host can create or sustain 100,000 live connections, and they provide no controlled benchmark for exactly that connection count. A server’s practical capacity also depends on host and process resource limits, memory, connection state, traffic pattern, and the work the application performs per connection.

Epoll registrations themselves consume kernel memory. The Linux man-pages project gives approximate per-watch costs of about 90 bytes on a 32-bit kernel and 160 bytes on a 64-bit kernel. These are estimates for registered watches, not a total memory budget per connection: connection buffers, application state, socket memory, and other resources add to the real cost.

The same epoll(7) manual documents a default-setting rule for fs.epoll.max_user_watches: the limit is derived from one quarter (4%) of available low memory divided by the registration cost. The actual limit depends on the running host and kernel, so inspect the target system rather than assume a default. This registration limit is one constraint among many, not a connection-capacity estimate.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What readiness semantics should you use?

select and poll provide level-triggered readiness. Epoll is level-triggered by default, and can also be configured for edge-triggered delivery with EPOLLET. In level-triggered mode, epoll has the same readiness semantics as poll, according to the epoll manual.

Level-triggered epoll

In level-triggered mode, readiness continues to be reported while the relevant condition remains true—for example, while data remains available to read. This is generally the simpler mode to adopt when converting an event loop to epoll.

Edge-triggered epoll

With EPOLLET, an application must not treat an event as a standing reminder that data remains available. Use nonblocking descriptors and continue reading or writing until the operation returns EAGAIN before waiting again. If the application consumes only some buffered data and then waits for a new edge, it can block even though unread data remains.

One-shot notifications

EPOLLONESHOT disables a descriptor after an event is delivered. To receive notifications for it again, rearm it through epoll_ctl using EPOLL_CTL_MOD. This behavior can be useful when an application wants to control when a descriptor becomes eligible for another notification, but it adds explicit rearming to the event loop.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

How should an event loop handle returned events?

epoll_wait returns up to the maximum number of ready events requested by the caller. If more descriptors are ready than fit in that batch, successive calls rotate through the ready set to help avoid starvation. Each event also carries a user-data field, which the application can use to associate the notification with its own descriptor or connection state.

A typical design registers a descriptor with the state needed by the application, waits for a bounded batch, and dispatches each returned event using that user data. In edge-triggered mode, the handler must drain the descriptor to EAGAIN; in one-shot mode, it must rearm the descriptor when appropriate. The exact event-loop structure depends on the application’s concurrency model and error-handling needs.

Which API should you choose?

  • Choose epoll on Linux when monitoring a very large set, especially if most descriptors are idle much of the time and you want to retrieve only ready events.
  • Choose level-triggered epoll first when you want epoll’s persistent registration model without edge-triggered drain-to-EAGAIN handling.
  • Consider poll for portable code or moderate descriptor sets where resubmitting an array is acceptable and you need to avoid select’s fixed glibc fd_set size.
  • Use select only when its interface constraints fit or portability to environments that require it matters; with glibc, it cannot represent descriptor numbers 1,024 and above through fd_set.
  • Check host limits before deployment, including the process’s descriptor limits and the host’s epoll watch limit; API choice alone does not size the server.

What is the practical conclusion?

For Linux applications that need to monitor a very large number of mostly idle descriptors, epoll is usually the right readiness API because registrations persist and waits return ready events rather than requiring the full watched set to be resubmitted. Poll remains a reasonable portable choice, while select’s glibc descriptor-set limit makes it unsuitable when descriptor numbers reach 1,024 or higher. None of these conclusions makes 100,000 live connections a guaranteed capacity: that must be established for the actual application and host.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.