Margaret found Timothy in the library's coordination room, staring at a wall covered in task dependency charts. 'The Event pattern works beautifully for simple signals,' he said, 'but I've hit something more complex. I need tasks to wait for specific conditions to become true, then wake up and check again. Events are too blunt - they're either set or not set. I need something more nuanced.'
'Ah,' Margaret smiled, 'you need a Condition. Think of it as a smart waiting room where tasks can sleep until they're told that something interesting has changed, then wake up to check if the change matters to them specifically.'
The Problem: When Events Aren't Enough
Timothy showed Margaret his code for managing a shared resource with capacity limits:
import asyncio
# Attempt 1: Using Event (doesn't quite work)
class SharedResource:
def __init__(self, capacity):
self.capacity = capacity
self.in_use = 0
self.available_event = asyncio.Event()
self.available_event.set() # Initially available
async def acquire(self):
while True:
await self.available_event.wait()
if self.in_use < self.capacity:
self.in_use += 1
if self.in_use >= self.capacity:
self.available_event.clear()
return
# Race condition: another task might have grabbed it ___eWEyOS5hMEFUaTZLMnRUUmlEUUZBVENfN3J0U3VsR19pT0plU2tnY2xZRDRTdXJMeFZ3eENsNC1EMnppZEdwNGNWamhGVXE0dmcxSncyNnJJeTZVc0lNWGVTQVg2SGxSR1BySjh1Y3pzLW5EVXlhckNkYUpqb0Fqd284cWY2NVdGSnJzbHhlVXpsV0tLRnFCQk5KNlo1RUt0RjdqRFpnN2MzaDA3dTVCX1ZRSXVCbnBSVWd5WF9zekp2dTYxdG1ySjlkckRpeGREdFRxc1lhQ2dZS0FZWVNBUkVTRlFIR1gyTWlFUVJIZ1FOQ2xNNjNpWXFPUlVvRVNnMDIwNg==___
# We need to wait again, but the event is still set!
async def release(self):
self.in_use -= 1
self.available_event.set()
async def demonstrate_event_problem():
resource = SharedResource(capacity=2)
async def worker(worker_id):
print(f'Worker {worker_id} trying to acquire')
await resource.acquire()
print(f'Worker {worker_id} acquired resource')
await asyncio.sleep(2)
await resource.release()
print(f'Worker {worker_id} released resource')
# Create 5 workers competing for 2 slots
await asyncio.gather(*[worker(i) for i in range(5)])
# asyncio.run(demonstrate_event_problem())
Top comments (0)