#!/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()