Skip to main content

Lib/selectors.py

Source:

cpython 3.14 @ ab2d84fe1023/Lib/selectors.py

selectors provides a high-level I/O event notification interface on top of select/poll/epoll/kqueue. It is the foundation of asyncio's event loop. DefaultSelector automatically picks the most efficient mechanism available on the current platform.

Map

LinesSymbolRole
1-60EVENT_READ, EVENT_WRITE, SelectorKeyConstants and named tuple
61-160BaseSelectorAbstract base class
161-240_BaseSelectorImplShared registration map
241-310SelectSelectorselect.select-based; available everywhere
311-390PollSelectorselect.poll-based; POSIX
391-470EpollSelectorselect.epoll-based; Linux
471-540DevpollSelector/dev/poll-based; Solaris
541-590KqueueSelector, DefaultSelectorkqueue (macOS/BSD); auto-selected best

Reading

SelectorKey

# CPython: Lib/selectors.py:28 SelectorKey
SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data'])
  • fileobj: the registered file object (socket, pipe, etc.)
  • fd: the file descriptor integer
  • events: bitmask of EVENT_READ | EVENT_WRITE
  • data: arbitrary user data attached at registration time

register and unregister

# CPython: Lib/selectors.py:188 _BaseSelectorImpl.register
def register(self, fileobj, events, data=None):
if fileobj in self._map:
raise KeyError("{!r} is already registered".format(fileobj))
key = SelectorKey(fileobj=fileobj, fd=self._fileobj_lookup(fileobj),
events=events, data=data)
self._fd_to_key[key.fd] = key
self._map[fileobj] = key
return key

_BaseSelectorImpl maintains two dicts: _fd_to_key (fd to key) and _map (fileobj to key). Subclasses add the fd to the OS-specific notification set in their register override.

select return value

select(timeout=None) returns a list of (key, events) pairs. events is a bitmask indicating which events are ready (may be a subset of the registered events).

# CPython: Lib/selectors.py:270 SelectSelector.select
def select(self, timeout=None):
...
r, w, _ = self._select(self._readers, self._writers, [], timeout)
r = set(r)
w = set(w)
ready = []
for fd in r | w:
events = 0
if fd in r:
events |= EVENT_READ
if fd in w:
events |= EVENT_WRITE
key = self._key_from_fd(fd)
if key:
ready.append((key, events & key.events))
return ready

EpollSelector

Uses select.epoll (Linux 2.5.44+). register calls self._epoll.register(fd, epoll_events). select calls self._epoll.poll(timeout, max_events) which returns [(fd, event), ...].

DefaultSelector

Alias to the best available selector on the current platform:

  • Linux: EpollSelector
  • macOS/BSD: KqueueSelector
  • Other POSIX: PollSelector
  • Windows: SelectSelector

gopy notes

Status: not yet ported. selectors is the critical path for asyncio. Go's net.Conn and os.File with goroutines obviate the need for explicit selector management in most cases, but a faithful selectors port is needed for CPython compatibility. The Go port would wrap golang.org/x/sys/unix.EpollWait (Linux) or unix.Kevent (macOS).