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.