select waits until monitored sockets become ready, then returns the sockets and events that need processing. A timeout returns no events after the specified interval. section 3.4
Used with selectors, select avoids repeatedly checking every socket. The operating system reports readiness efficiently, allowing one loop to serve multiple non-blocking connections with low CPU usage. section 3.4 section 3.7
A selector-driven echo server
Register a non-blocking server socket for read events, call selector.select(timeout=1), and process each returned event. An empty result allows the loop to wait without busy-spinning. section 3.4
Listing 3.7 Using selectors to build a non-blocking server
import selectors
import socket
from selectors import SelectorKey
from typing import List, Tuple
selector = selectors.DefaultSelector()
server_socket = socket.socket()
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_address = ('127.0.0.1', 8000)
server_socket.setblocking(False)
server_socket.bind(server_address)
server_socket.listen()
selector.register(server_socket, selectors.EVENT_READ)
while True:
events: List[Tuple[SelectorKey, int]] = selector.select(timeout=1) #1
if len(events) == 0: #2
print('No events, waiting a bit more!')
for event, _ in events:
event_socket = event.fileobj #3
if event_socket == server_socket: #4
connection, address = server_socket.accept()
connection.setblocking(False)
print(f"I got a connection from {address}")
selector.register(connection, selectors.EVENT_READ) #5
else:
data = event_socket.recv(1024) #6
print(f"I got some data: {data}")
event_socket.send(data)
Runnable code shows registration, timed select calls, empty-event handling, and dispatch between new connections and client data. section 3.4








