2023-05-15 23:56:53 +02:00
|
|
|
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")
|
|
|
|
|
|
|
|
|
2023-05-17 22:28:29 +02:00
|
|
|
async def main_sem(n: int, k: int):
|
2023-05-15 23:56:53 +02:00
|
|
|
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")
|
|
|
|
|
|
|
|
|
2023-05-17 22:28:29 +02:00
|
|
|
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")
|
|
|
|
|
|
|
|
|
2023-05-15 23:56:53 +02:00
|
|
|
# Should exit in about k seconds
|
2023-05-17 22:28:29 +02:00
|
|
|
structio.run(main_sem, 3, 5)
|
|
|
|
# Same here, should exit in k seconds, but
|
2023-06-12 11:41:38 +02:00
|
|
|
# it'll run one task at a time (also fewer tasks)
|
2023-05-17 22:28:29 +02:00
|
|
|
structio.run(main_lock, 10)
|
|
|
|
# This should exit in about 2k seconds
|
|
|
|
structio.run(main_rlock, 5)
|