structio/tests/semaphores.py

74 lines
2.7 KiB
Python

import structio
async def child(i: int, sem: structio.Semaphore):
async with sem:
print(f"[child {i}] Entered critical section")
await structio.sleep(1)
print(f"[child {i}] Exited critical section")
async def main_sem(n: int, k: int):
assert isinstance(n, int) and n > 0
assert isinstance(k, int) and k > 1
print(f"[main] Parent is alive, creating semaphore of size {n}")
semaphore = structio.Semaphore(n)
t = structio.clock()
async with structio.create_pool() as pool:
print(f"[main] Spawning {n * k} children")
for i in range(1, (n * k) + 1):
pool.spawn(child, i, semaphore)
print("[main] All children spawned, waiting for completion")
# Since our semaphore has a limit of n tasks that
# can acquire it concurrently, we should see at most
# n instances of child running at any given time,
# like in batches
print(f"[main] Done in {structio.clock() - t:.2f} seconds")
async def main_lock(k: int):
assert isinstance(k, int) and k > 1
print(f"[main] Parent is alive, creating lock")
lock = structio.Lock()
t = structio.clock()
async with structio.create_pool() as pool:
print(f"[main] Spawning {k} children")
for i in range(1, k + 1):
# Locks are implemented as simple binary semaphores
# and have an identical API, so they can be used
# interchangeably
pool.spawn(child, i, lock)
print("[main] All children spawned, waiting for completion")
print(f"[main] Done in {structio.clock() - t:.2f} seconds")
async def recursive_child(i: int, sem: structio.Semaphore, kapow: bool = False):
async with sem:
print(f"[{'copy of ' if kapow else ''}child {i}] Entered critical section")
if kapow:
await recursive_child(i, sem)
await structio.sleep(1)
print(f"[{'copy of ' if kapow else ''}child {i}] Exited critical section")
async def main_rlock(k: int):
assert isinstance(k, int) and k > 1
print(f"[main] Parent is alive, creating recursive lock")
lock = structio.RLock()
t = structio.clock()
async with structio.create_pool() as pool:
print(f"[main] Spawning {k} children")
for i in range(1, k + 1):
pool.spawn(recursive_child, i, lock, True)
print("[main] All children spawned, waiting for completion")
print(f"[main] Done in {structio.clock() - t:.2f} seconds")
# Should exit in about k seconds
structio.run(main_sem, 3, 5)
# Same here, should exit in k seconds, but
# it'll run one task at a time (also fewer tasks)
structio.run(main_lock, 10)
# This should exit in about 2k seconds
structio.run(main_rlock, 5)