Posted to tcl by JMN at Thu Jul 31 03:29:23 GMT 2025view raw
- import sys
- import time
- import asyncio
- from subprocess import Popen, PIPE
- RESET = "\033[0m"
- C = "\033[32m" # Child color green
- P = "\033[33m" # Parent color yellow
- def usage():
- print("Usage:")
- print(" stdin_race.py pump <persecond> <maxcount>")
- print(" stdin_race.py parent")
- print(" stdin_race.py child <delay_ms>")
- print("\nExample:")
- print(" python stdin_race.py pump 35 50 | python stdin_race.py parent")
- sys.exit(1)
- async def pump(persecond, maxcount):
- if persecond > 1000:
- print("WARNING: (>1000) sub-millisecond scheduling not available - will go full speed", file=sys.stderr)
- await asyncio.sleep(0.5)
- counter = -1
- ms = 1000 / persecond
- async def pump_emit():
- nonlocal counter
- try:
- counter += 1
- print(f".{counter}", end="", flush=True)
- except BrokenPipeError:
- return False
- return True
- async def pump_schedule():
- nonlocal counter
- while maxcount <= 0 or counter < maxcount - 1:
- if not await pump_emit():
- break
- await asyncio.sleep(ms / 1000)
- print("pump-done", file=sys.stderr, flush=True)
- await pump_schedule()
- async def parent():
- print(f"{P}parent{RESET}", file=sys.stderr, flush=True)
- await asyncio.sleep(0.25)
- # Read the first chunk from stdin
- parent_chunk1 = sys.stdin.read(8)
- print(f"{P}{parent_chunk1}{RESET}", file=sys.stderr, flush=True)
- # Launch the child process
- child_proc = Popen(
- [sys.executable, __file__, "child", "150"],
- stdin=PIPE, stdout=PIPE, stderr=sys.stderr, text=True
- )
- # Forward stdin to the child process
- while True:
- chunk = sys.stdin.read(1)
- if not chunk:
- break
- print(f"{chunk}", file=sys.stdout, end='', flush=True)
- # Wait for the child process to finish
- child_proc.stdin.close()
- child_proc.wait()
- print("parent-tail-read", file=sys.stderr, flush=True)
- while True:
- chunk = sys.stdin.read(1)
- if not chunk:
- break
- print(chunk, end="", file=sys.stderr, flush=True)
- print(f"\n{P}parent-done{RESET}", flush=True)
- async def child(delay_ms):
- print(f"\n{C}child{RESET}", file=sys.stderr, flush=True)
- await asyncio.sleep(delay_ms / 1000)
- # Read from stdin
- chunk = sys.stdin.read(16)
- print(f"{C}{chunk}{RESET}", file=sys.stderr, flush=True)
- print("child-done", file=sys.stderr, flush=True)
- sys.exit(0)
- def main():
- if len(sys.argv) < 2:
- usage()
- role = sys.argv[1]
- if role == "pump":
- if len(sys.argv) != 4:
- usage()
- persecond = int(sys.argv[2])
- maxcount = int(sys.argv[3])
- asyncio.run(pump(persecond, maxcount))
- elif role == "parent":
- if len(sys.argv) != 2:
- usage()
- asyncio.run(parent())
- elif role == "child":
- if len(sys.argv) != 3:
- usage()
- delay_ms = int(sys.argv[2])
- asyncio.run(child(delay_ms))
- else:
- usage()
- if __name__ == "__main__":
- main()
Add a comment