63 lines
1.8 KiB
Python
63 lines
1.8 KiB
Python
from collections import deque
|
|
from threading import Condition, Lock
|
|
from typing import Deque
|
|
|
|
from reactivex.internal.priorityqueue import PriorityQueue
|
|
|
|
from .scheduleditem import ScheduledItem
|
|
|
|
|
|
class Trampoline:
|
|
def __init__(self) -> None:
|
|
self._idle: bool = True
|
|
self._queue: PriorityQueue[ScheduledItem] = PriorityQueue()
|
|
self._lock: Lock = Lock()
|
|
self._condition: Condition = Condition(self._lock)
|
|
|
|
def idle(self) -> bool:
|
|
with self._lock:
|
|
return self._idle
|
|
|
|
def run(self, item: ScheduledItem) -> None:
|
|
with self._lock:
|
|
self._queue.enqueue(item)
|
|
if self._idle:
|
|
self._idle = False
|
|
else:
|
|
self._condition.notify()
|
|
return
|
|
try:
|
|
self._run()
|
|
finally:
|
|
with self._lock:
|
|
self._idle = True
|
|
self._queue.clear()
|
|
|
|
def _run(self) -> None:
|
|
ready: Deque[ScheduledItem] = deque()
|
|
while True:
|
|
with self._lock:
|
|
while len(self._queue) > 0:
|
|
item: ScheduledItem = self._queue.peek()
|
|
if item.duetime <= item.scheduler.now:
|
|
self._queue.dequeue()
|
|
ready.append(item)
|
|
else:
|
|
break
|
|
|
|
while len(ready) > 0:
|
|
item = ready.popleft()
|
|
if not item.is_cancelled():
|
|
item.invoke()
|
|
|
|
with self._lock:
|
|
if len(self._queue) == 0:
|
|
break
|
|
item = self._queue.peek()
|
|
seconds = (item.duetime - item.scheduler.now).total_seconds()
|
|
if seconds > 0.0:
|
|
self._condition.wait(seconds)
|
|
|
|
|
|
__all__ = ["Trampoline"]
|