Blocking means that execution waits for an operation to finish before continuing. Slow I/O, such as reading from a network or waiting for user input, can leave an application frozen or unresponsive because later work cannot run. section 1.1
Sockets are blocking by default: accept, read, or write can halt the application until data arrives, an error occurs, or a timeout expires. Non-blocking sockets return control immediately and let the operating system report readiness later. section 1.6.1
One client holds up another
A simple echo server accepts a client and then waits in recv for that client’s message. While it waits, a second telnet client cannot be processed. Marking the socket non-blocking prevents the receive operation from stopping the next loop iteration. section 3.2.2
Blocking calls are especially important in asyncio because they block its event-loop thread. Wrapping requests.get or time.sleep in async def does not make them asynchronous: tasks created together still execute serially around the blocking call. Use coroutine-based libraries such as aiohttp, or move unavoidable synchronous work into a thread pool. section 2.7.2 section 2.10
Figure 1.8 Making a non-blocking I/O request returns immediately and tells the O/S to watch sockets for data. This allows execute_other_code() to run right away instead of waiting for the I/O requests to finish. Later, we can be alerted when I/O is complete and process the response.
The figure contrasts an I/O request that blocks with one that returns immediately while the operating system watches for socket readiness. section 1.6.1
Existing synchronous libraries remain usable when their blocking operations run in threads. In asynchronous web views, sync_to_async provides a similar bridge, but thread-sensitive mode can still block the application’s main worker when shared state requires one thread. section 7.0 section 9.4.1








