Files
Solax/myenv/lib/python3.12/site-packages/reactivex/scheduler/newthreadscheduler.py
2024-09-13 09:46:28 +02:00

137 lines
4.1 KiB
Python

import logging
import threading
from datetime import datetime
from typing import Optional, TypeVar
from reactivex import abc, typing
from reactivex.disposable import Disposable
from reactivex.internal.concurrency import default_thread_factory
from .eventloopscheduler import EventLoopScheduler
from .periodicscheduler import PeriodicScheduler
_TState = TypeVar("_TState")
log = logging.getLogger("Rx")
class NewThreadScheduler(PeriodicScheduler):
"""Creates an object that schedules each unit of work on a separate thread."""
def __init__(
self, thread_factory: Optional[typing.StartableFactory] = None
) -> None:
super().__init__()
self.thread_factory: typing.StartableFactory = (
thread_factory or default_thread_factory
)
def schedule(
self, action: typing.ScheduledAction[_TState], state: Optional[_TState] = None
) -> abc.DisposableBase:
"""Schedules an action to be executed.
Args:
action: Action to be executed.
state: [Optional] state to be given to the action function.
Returns:
The disposable object used to cancel the scheduled action
(best effort).
"""
scheduler = EventLoopScheduler(
thread_factory=self.thread_factory, exit_if_empty=True
)
return scheduler.schedule(action, state)
def schedule_relative(
self,
duetime: typing.RelativeTime,
action: typing.ScheduledAction[_TState],
state: Optional[_TState] = None,
) -> abc.DisposableBase:
"""Schedules an action to be executed after duetime.
Args:
duetime: Relative time after which to execute the action.
action: Action to be executed.
state: [Optional] state to be given to the action function.
Returns:
The disposable object used to cancel the scheduled action
(best effort).
"""
scheduler = EventLoopScheduler(
thread_factory=self.thread_factory, exit_if_empty=True
)
return scheduler.schedule_relative(duetime, action, state)
def schedule_absolute(
self,
duetime: typing.AbsoluteTime,
action: typing.ScheduledAction[_TState],
state: Optional[_TState] = None,
) -> abc.DisposableBase:
"""Schedules an action to be executed at duetime.
Args:
duetime: Absolute time at which to execute the action.
action: Action to be executed.
state: [Optional] state to be given to the action function.
Returns:
The disposable object used to cancel the scheduled action
(best effort).
"""
dt = self.to_datetime(duetime)
return self.schedule_relative(dt - self.now, action, state=state)
def schedule_periodic(
self,
period: typing.RelativeTime,
action: typing.ScheduledPeriodicAction[_TState],
state: Optional[_TState] = None,
) -> abc.DisposableBase:
"""Schedules a periodic piece of work.
Args:
period: Period in seconds or timedelta for running the
work periodically.
action: Action to be executed.
state: [Optional] Initial state passed to the action upon
the first iteration.
Returns:
The disposable object used to cancel the scheduled
recurring action (best effort).
"""
seconds: float = self.to_seconds(period)
timeout: float = seconds
disposed: threading.Event = threading.Event()
def run() -> None:
nonlocal state, timeout
while True:
if timeout > 0.0:
disposed.wait(timeout)
if disposed.is_set():
return
time: datetime = self.now
state = action(state)
timeout = seconds - (self.now - time).total_seconds()
thread = self.thread_factory(run)
thread.start()
def dispose() -> None:
disposed.set()
return Disposable(dispose)