From a34aaf98d21c6cd3d98425dc17d4e6e373aa41a3 Mon Sep 17 00:00:00 2001 From: goodboy Date: Thu, 2 Jul 2026 12:10:27 -0400 Subject: [PATCH] Add `to_actor` one-shot parallelism example Demo both flavors of the new API in a runnable script (auto-collected by `test_docs_examples.py`), - the fully-implicit one-shot which boots (and tears down) the actor-runtime around a single `to_actor.run()` call, - the concurrent "worker-pool-ish" prime-check pattern: a local `trio` task nursery scheduling one-shots against a shared caller-managed `an`, mirroring (in miniature) the neighboring `concurrent_actors_primes.py` example per issue #477. (this patch was generated in some part by [`claude-code`][claude-code-gh]) [claude-code-gh]: https://github.com/anthropics/claude-code --- examples/parallelism/to_actor_one_shots.py | 83 ++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 examples/parallelism/to_actor_one_shots.py diff --git a/examples/parallelism/to_actor_one_shots.py b/examples/parallelism/to_actor_one_shots.py new file mode 100644 index 00000000..5edc6a21 --- /dev/null +++ b/examples/parallelism/to_actor_one_shots.py @@ -0,0 +1,83 @@ +''' +`tractor.to_actor.run()`: one-shot single-task subactor +invocation, the SC-parallelism sibling of +`trio.to_thread.run_sync()` (and `anyio.to_process`). + +Each call spawns a subactor, schedules the async fn as +its lone remote task, waits on the result and reaps the +subactor. Concurrency composes the plain `trio` way: +schedule multiple one-shot calls in a local task nursery +against a shared actor-nursery; any remote error raises +directly in the task which scheduled it. + +''' +import math + +import tractor +import trio + + +async def is_prime( + n: int, +) -> bool: + if n < 2: + return False + if n == 2: + return True + if n % 2 == 0: + return False + + sqrt_n = int(math.floor(math.sqrt(n))) + for i in range(3, sqrt_n + 1, 2): + if n % i == 0: + return False + return True + + +async def main() -> None: + + # fully implicit one-shot: boots the actor-runtime, + # spawns a subactor, runs the task, reaps the + # subactor, tears the runtime back down. + assert await tractor.to_actor.run( + is_prime, + n=2, + ) + + # the "worker-pool-ish" pattern from the original + # `concurrent.futures` example: one subactor per + # input, all concurrent, results and errors + # collected by caller-side tasks. + results: dict[int, bool] = {} + + async def check( + an: tractor.ActorNursery, + n: int, + i: int, + ) -> None: + results[n] = await tractor.to_actor.run( + is_prime, + an=an, + name=f'prime_checker_{i}', + n=n, + ) + + inputs: list[int] = [ + 7, + 8, + 3691, + 3693, + ] + async with ( + tractor.open_nursery() as an, + trio.open_nursery() as tn, + ): + for i, n in enumerate(inputs): + tn.start_soon(check, an, n, i) + + for n, prime in sorted(results.items()): + print(f'{n} is prime: {prime}') + + +if __name__ == '__main__': + trio.run(main)