79 lines
2.5 KiB
Python
79 lines
2.5 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from typing import Self, Any, Callable, Sequence, Optional
|
|
from threading import Thread, Lock
|
|
from Utils.Checks import Check
|
|
from Utils.Common import Common
|
|
|
|
class QueueItemModel:
|
|
def __init__(self:Self, i:int, callback:Callable[[Callable[[], None]], None], *arguments:list[Any|None]) -> None:
|
|
self.i:int = i
|
|
self.callback:Callable[[Callable[[], None]], None] = callback
|
|
self.arguments:list[Any|None] = arguments
|
|
self.executing:bool = False
|
|
self.thread:Thread|None = None
|
|
|
|
class QueuesModel:
|
|
|
|
def __init__(self:Self, key:str, inputs:Optional[int|dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
|
|
|
if Check.is_integer(inputs):
|
|
inputs = {"maximum" : inputs}
|
|
|
|
self.key:str = key
|
|
self.items:dict[int, QueueItemModel] = {}
|
|
self.i:int = 0
|
|
self.p:int = 0
|
|
self.maximum:int = Common.get_value(("maximum", "maximum_concurrent", "maximum_simultaneous"), inputs, 1)
|
|
self.current:int = 0
|
|
|
|
def add(self:Self, callback:Callable[[Callable[[], None]], None], *arguments:list[Any|None]) -> int|None:
|
|
|
|
i:int|None = None
|
|
|
|
if Check.is_function(callback):
|
|
with Lock():
|
|
self.items[i := self.i] = QueueItemModel(self.i, callback, *arguments)
|
|
self.i += 1
|
|
|
|
self.next()
|
|
|
|
return i
|
|
|
|
def cancel(self:Self, i:int) -> bool:
|
|
with Lock():
|
|
if i in self.items and not self.items[i].executing:
|
|
del self.items[i]
|
|
return True
|
|
return False
|
|
|
|
def cancel_all(self:Self) -> None:
|
|
with Lock():
|
|
for i in list(self.items.keys()):
|
|
if not self.items[i].executing:
|
|
del self.items[i]
|
|
|
|
def __end(self:Self, p:int) -> None:
|
|
with Lock():
|
|
self.current -= 1
|
|
del self.items[p]
|
|
self.next()
|
|
|
|
def next(self:Self) -> None:
|
|
while self.p < self.i and self.current < self.maximum:
|
|
|
|
item:QueueItemModel
|
|
p:int|None = None
|
|
|
|
with Lock():
|
|
p = min((item.i for item in self.items.values() if not item.executing), default=None)
|
|
if p is None:
|
|
return
|
|
item = self.items[p]
|
|
item.executing = True
|
|
self.p = p
|
|
self.current += 1
|
|
|
|
item.thread = Thread(target = lambda:item.callback(lambda *results:self.__end(p, *results), *item.arguments))
|
|
item.thread.start() |