selectors chooses an efficient multiplexing implementation for the operating system and exposes one interface. A loop can wait for read or write readiness across many descriptors without blocking on one.

Practical example

import selectors
import socket

left, right = socket.socketpair()
with selectors.DefaultSelector() as selector:
    selector.register(left, selectors.EVENT_READ)
    right.sendall(b"ready")
    for key, _ in selector.select(timeout=1):
        print(key.fileobj.recv(1024).decode())
left.close()
right.close()

Register interest instead of polling

Associate every socket with required events and a state object. select(timeout) sleeps until work is ready or the deadline expires, avoiding a CPU-intensive empty loop.

Operations can still be partial

Write readiness does not guarantee that an entire buffer will be sent. Keep an output queue, process what the socket accepts, and modify registered events as state changes.

Cleanup and portability

Unregister a descriptor before closing it. Regular files and pipes behave differently across operating systems, so validate each resource type on supported platforms.

Keep learning

Strengthen the foundation with asynchronous Python. The official Python documentation, accessed July 22, 2026, documents the API, limitations, and version differences.