liveBook · Manning

Semaphore

As explained in Python Concurrency with asyncio

A semaphore is a synchronization primitive that maintains a counter and permits a bounded number of execution contexts to access a resource concurrently.

A semaphore is a synchronization primitive that maintains a counter and permits only a bounded number of execution contexts to access a resource concurrently. Each acquire consumes a permit; each release restores one. When no permits remain, further acquisitions wait. A lock is the special case with a limit of one. section 11.3

Use semaphores when concurrent work must fit within a finite capacity:

  • Limit database connections, CPU-intensive work, or requests to an external API. section 11.0 section 11.3
  • Wrap an asyncio operation in async with semaphore so acquisition and release are paired automatically. section 11.3
  • Choose BoundedSemaphore when manual release logic must detect excess releases; an invalid release raises ValueError. section 11.3.1

Allow two tasks at a time

Create Semaphore(2), start four coroutines with asyncio.gather, and acquire the semaphore inside each coroutine. The first two tasks proceed while the other two wait; completed tasks release permits so the waiting tasks can continue. section 11.3

Listing 11.6 Using semaphores
import asyncio
from asyncio import Semaphore
 
 
async def operation(semaphore: Semaphore):
    print('Waiting to acquire semaphore...')
    async with semaphore:
        print('Semaphore acquired!')
        await asyncio.sleep(2)
    print('Semaphore released!')
 
 
async def main():
    semaphore = Semaphore(2)
    await asyncio.gather(*[operation(semaphore) for _ in range(4)])
 
asyncio.run(main())

Runnable asyncio code demonstrates four operations sharing two semaphore permits, including acquisition, simulated work, and automatic release. section 11.3

How Python Concurrency with asyncio covers it

How deep it goes
Explains permit counting, blocking at zero, lock equivalence, async usage, and excess-release detection through BoundedSemaphore.
Examples
Uses asyncio tasks, limited API requests, database connections, and CPU-bound gpg subprocesses as concrete applications.
What it assumes
Assumes basic asyncio coroutine and task usage while defining acquisition, release, waiting, and bounded access.
What you can do after
Apply asyncio.Semaphore or BoundedSemaphore to constrain concurrent operations and diagnose incorrect manual release logic.
How it connects
Connects semaphores with locks, traffic shaping, shared resources, database connection pools, and ProcessPoolExecutor worker limits.

Also explained in

Compare how 5 books explain semaphore →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Python Concurrency with asyncio. The section links point to the parts of the book it draws on.