By default, Pykka builds on top of Python's regular threading concurrency model,
via the standard library module threading.
Pykka 2 and earlier shipped with some alternative implementations that
ran on top of
gevent or
eventlet.
These alternative implementations were removed in Pykka 3.
Note that Pykka does no attempt at supporting a mix of concurrency runtimes.
Threading runtime
The default threading runtime has no dependencies other than Pykka itself and
the Python standard library.
Implementation of Future for use with regular Python threads.
Mutable messages
The future does not make a copy of the object which is
set() on it. It is the setters responsibility to
only pass immutable objects or make a copy of the object before setting
it on the future.
Version changed: Pykka 0.14
Previously, the encapsulated value was a copy made with
copy.deepcopy(), unless the encapsulated value was a
future, in which case the original future was encapsulated.
classThreadingFuture(Future[T]):"""Implementation of [`Future`][pykka.Future] for use with regular Python threads. /// warning | Mutable messages The future *does not* make a copy of the object which is [`set()`][pykka.Future.set] on it. It is the setters responsibility to only pass immutable objects or make a copy of the object before setting it on the future. /// /// note | Version changed: Pykka 0.14 Previously, the encapsulated value was a copy made with [`copy.deepcopy()`][copy.deepcopy], unless the encapsulated value was a future, in which case the original future was encapsulated. /// """def__init__(self)->None:super().__init__()self._condition:threading.Condition=threading.Condition()self._result:ThreadingFutureResult|None=Nonedefget(self,*,timeout:float|None=None,)->Any:deadline:float|None=NoneiftimeoutisNoneelsetime.monotonic()+timeoutwithself._condition:try:returnsuper().get(timeout=timeout)exceptNotImplementedError:passwhileself._resultisNone:remaining=(deadline-time.monotonic()ifdeadlineisnotNoneelseNone)ifremainingisnotNoneandremaining<=0.0:msg=f"{timeout} seconds"raiseTimeout(msg)self._condition.wait(timeout=remaining)ifself._result.exc_infoisnotNone:(exc_type,exc_value,exc_traceback)=self._result.exc_infoassertexc_typeisnotNoneifexc_valueisNone:exc_value=exc_type()ifexc_value.__traceback__isnotexc_traceback:raiseexc_value.with_traceback(exc_traceback)raiseexc_valuereturnself._result.valuedefset(self,value:Any|None=None,)->None:withself._condition:ifself._resultisnotNoneorself._get_hookisnotNone:raisequeue.Fullself._result=ThreadingFutureResult(value=value)self._condition.notify_all()defset_exception(self,exc_info:OptExcInfo|None=None,)->None:assertexc_infoisNoneorlen(exc_info)==3ifexc_infoisNone:exc_info=sys.exc_info()withself._condition:ifself._resultisnotNoneorself._get_hookisnotNone:raisequeue.Fullself._result=ThreadingFutureResult(exc_info=exc_info)self._condition.notify_all()defset_get_hook(self,func:GetHookFunc[T],)->None:withself._condition:ifself._resultisnotNone:raisequeue.Fullsuper().set_get_hook(func)self._condition.notify_all()
classThreadingActor(Actor):"""Implementation of [`Actor`][pykka.Actor] using regular Python threads."""use_daemon_thread:ClassVar[bool]=False""" A boolean value indicating whether this actor is executed on a thread that is a daemon thread (`True`) or not (`False`). This must be set before [`Actor.start()`][pykka.Actor.start] is called, otherwise [`RuntimeError`][RuntimeError] is raised. The entire Python program exits when no alive non-daemon threads are left. This means that an actor running on a daemon thread may be interrupted at any time, and there is no guarantee that cleanup will be done or that [`Actor.on_stop()`][pykka.Actor.on_stop] will be called. Actors do not inherit the daemon flag from the actor that made it. It always has to be set explicitly for the actor to run on a daemonic thread. """@staticmethoddef_create_actor_inbox()->ActorInbox:inbox:queue.Queue[Envelope[Any]]=queue.Queue()returninbox@staticmethoddef_create_future()->Future[Any]:returnThreadingFuture()def_start_actor_loop(self)->None:thread=threading.Thread(target=self._actor_loop,name=f"{self.__class__.__name__}-{next(_actor_thread_counter)}",)thread.daemon=self.use_daemon_threadthread.start()
use_daemon_threadclass-attribute
use_daemon_thread:bool=False
A boolean value indicating whether this actor is executed on a thread that
is a daemon thread (True) or not (False). This must be set before
Actor.start() is called, otherwise
RuntimeError is raised.
The entire Python program exits when no alive non-daemon threads are left.
This means that an actor running on a daemon thread may be interrupted at
any time, and there is no guarantee that cleanup will be done or that
Actor.on_stop() will be called.
Actors do not inherit the daemon flag from the actor that made it. It
always has to be set explicitly for the actor to run on a daemonic thread.