Skip to content

Semaphores (limit concurrency)

A semaphore controls access to a limited resource.

Example: only 3 workers may access an API at once.

semaphore.py
import threading
import time
 
sem = threading.Semaphore(3)
 
 
def worker(i: int) -> None:
    with sem:
        print("start", i)
        time.sleep(0.5)
        print("end", i)
 
 
threads = [threading.Thread(target=worker, args=(i,)) for i in range(10)]
for t in threads:
    t.start()
for t in threads:
    t.join()
sketch A semaphore caps how many run at once p5.js
Twelve jobs of 0.05 s each against a semaphore. The permit count is a hard ceiling on in-flight work, so the jobs go through in waves and the total time is roughly waves multiplied by job length. Measured: with 2 permits the peak in-flight was exactly 2 and the run took 0.31 s against a 0.30 s ideal; with 3 permits, peak 3 and 0.21 s against 0.20 s. Click to switch the permit count.

BoundedSemaphore raises an error if you release too many times.

Use it to catch bugs.

bounded_semaphore.py
import threading
 
sem = threading.BoundedSemaphore(1)
sem.acquire()
sem.release()
# sem.release()  # would raise ValueError

Exercise 2 – Semaphore as Context Manager

Section titled “Exercise 2 – Semaphore as Context Manager”

pch.coffeeTagline

pch.coffeeCta

pch.feedbackHeading

pch.feedbackSubheading