Source code for katharos.concurrency.csp.csp

from __future__ import annotations

from katharos.concurrency.base_threading_backend import BaseThreadingBackend
from katharos.concurrency.threading_backend import default_backend

from .channel import Channel
from .go import Go


[docs] class CSPRuntime: """A CSP runtime that binds channels and goroutines to one backend. ``CSPRuntime`` bundles Katharos' Communicating Sequential Processes primitives -- :class:`~katharos.concurrency.csp.Channel` and :class:`~katharos.concurrency.csp.Go` -- around a single :class:`~katharos.concurrency.BaseThreadingBackend`. Channels created via :attr:`Channel` and work launched via :attr:`go` all run on (and synchronize through) that one backend, so the whole concurrency model is swappable in a single place. The two members are: - :attr:`Channel`: a backend-bound channel class. Subscript it with the element type and call it to construct a channel: ``ch = csp.Channel[int](capacity=1)``. The ``backend`` is supplied automatically, so callers never pass it. - :attr:`go`: a backend-bound :class:`~katharos.concurrency.csp.Go` launcher. Call it to run work concurrently (``csp.go(fn, *args)``) or use it as a ``with`` block for structured concurrency. Examples: >>> from katharos.concurrency.threading_backend import ThreadingBackend >>> csp = CSPRuntime(ThreadingBackend()) >>> ch = csp.Channel[int](capacity=1) >>> _ = csp.go(ch.send, 42) >>> ch.recv() Success(42) Used as a structured-concurrency scope, the block waits for everything launched inside it: >>> ch = csp.Channel[int]() >>> with csp.go: ... _ = csp.go(ch.send, 1) ... received = ch.recv() >>> received Success(1) """
[docs] def __init__(self, backend: BaseThreadingBackend | None = None) -> None: """Initialize a CSP runtime bound to a backend. Args: backend: The threading backend that channels and goroutines from this runtime use. Defaults to the shared :func:`~katharos.concurrency.threading_backend.default_backend`. """ self._backend = backend or default_backend() self.go = Go(self._backend) _backend = self._backend class BoundChannel[A](Channel[A]): """A :class:`Channel` pre-bound to this runtime's backend.""" def __init__(self, capacity: int = 0) -> None: super().__init__(capacity, backend=_backend) self.Channel = BoundChannel
@property def backend(self) -> BaseThreadingBackend: """The threading backend shared by this runtime's channels and goroutines.""" return self._backend
csp = CSPRuntime() """The default CSP runtime, bound to the default threading backend."""