simplify taskman, and add .run_on_main()
This commit is contained in:
parent
8236f800ae
commit
be3393fcb4
@ -933,7 +933,7 @@ class DownloaderInstaller(QObject):
|
||||
self.on_done = on_done
|
||||
|
||||
self.mgr.mw.progress.start(immediate=True, parent=self.parent())
|
||||
self.mgr.mw.taskman.run(self._download_all, self._download_done)
|
||||
self.mgr.mw.taskman.run_in_background(self._download_all, self._download_done)
|
||||
|
||||
def _progress_callback(self, up: int, down: int) -> None:
|
||||
self.dl_bytes += down
|
||||
@ -1063,7 +1063,7 @@ def check_for_updates(
|
||||
|
||||
on_done(client, result)
|
||||
|
||||
mgr.mw.taskman.run(check, update_info_received)
|
||||
mgr.mw.taskman.run_in_background(check, update_info_received)
|
||||
|
||||
|
||||
def handle_update_info(
|
||||
|
@ -224,7 +224,7 @@ class SimpleProcessPlayer(Player): # pylint: disable=abstract-method
|
||||
self._process: Optional[subprocess.Popen] = None
|
||||
|
||||
def play(self, tag: AVTag, on_done: OnDoneCallback) -> None:
|
||||
self._taskman.run(
|
||||
self._taskman.run_in_background(
|
||||
lambda: self._play(tag), lambda res: self._on_done(res, on_done)
|
||||
)
|
||||
|
||||
|
@ -7,39 +7,40 @@ Helper for running tasks on background threads.
|
||||
|
||||
from concurrent.futures import Future
|
||||
from concurrent.futures.thread import ThreadPoolExecutor
|
||||
from dataclasses import dataclass
|
||||
from threading import Lock
|
||||
from typing import Any, Callable, Dict, List, Optional
|
||||
|
||||
from PyQt5.QtCore import QObject, pyqtSignal
|
||||
|
||||
|
||||
@dataclass
|
||||
class PendingDoneCallback:
|
||||
callback: Callable[[Any], None]
|
||||
future: Future
|
||||
Closure = Callable[[], None]
|
||||
|
||||
|
||||
class TaskManager(QObject):
|
||||
_results_available = pyqtSignal()
|
||||
_closures_pending = pyqtSignal()
|
||||
|
||||
def __init__(self):
|
||||
QObject.__init__(self)
|
||||
|
||||
self._executor = ThreadPoolExecutor()
|
||||
self._closures: List[Closure] = []
|
||||
self._closures_lock = Lock()
|
||||
self._closures_pending.connect(self._on_closures_pending) # type: ignore
|
||||
|
||||
self._pending_callbacks: List[PendingDoneCallback] = []
|
||||
def run_on_main(self, closure: Closure):
|
||||
"Run the provided closure on the main thread."
|
||||
with self._closures_lock:
|
||||
self._closures.append(closure)
|
||||
self._closures_pending.emit() # type: ignore
|
||||
|
||||
self._results_lock = Lock()
|
||||
self._results_available.connect(self._drain_results) # type: ignore
|
||||
|
||||
def run(
|
||||
def run_in_background(
|
||||
self,
|
||||
task: Callable,
|
||||
on_done: Optional[Callable],
|
||||
on_done: Optional[Callable[[Future], None]] = None,
|
||||
args: Optional[Dict[str, Any]] = None,
|
||||
) -> Future:
|
||||
"""Run task on a background thread, calling on_done on the main thread if provided.
|
||||
"""Run task on a background thread.
|
||||
|
||||
If on_done is provided, it will be called on the main thread with
|
||||
the completed future.
|
||||
|
||||
Args if provided will be passed on as keyword arguments to the task callable."""
|
||||
if args is None:
|
||||
@ -48,30 +49,17 @@ class TaskManager(QObject):
|
||||
fut = self._executor.submit(task, **args)
|
||||
|
||||
if on_done is not None:
|
||||
|
||||
def done_closure(completed_future: Future) -> None:
|
||||
self._handle_done_callback(completed_future, on_done)
|
||||
|
||||
fut.add_done_callback(done_closure)
|
||||
fut.add_done_callback(
|
||||
lambda future: self.run_on_main(lambda: on_done(future))
|
||||
)
|
||||
|
||||
return fut
|
||||
|
||||
def _handle_done_callback(self, future: Future, callback: Callable) -> None:
|
||||
"""When future completes, schedule its callback to run on the main thread."""
|
||||
# add result to the queue
|
||||
with self._results_lock:
|
||||
self._pending_callbacks.append(
|
||||
PendingDoneCallback(callback=callback, future=future)
|
||||
)
|
||||
def _on_closures_pending(self):
|
||||
"""Run any pending closures. This runs in the main thread."""
|
||||
with self._closures_lock:
|
||||
closures = self._closures
|
||||
self._closures = []
|
||||
|
||||
# and tell the main thread to flush the queue
|
||||
self._results_available.emit() # type: ignore
|
||||
|
||||
def _drain_results(self):
|
||||
"""Fires pending callbacks in the main thread."""
|
||||
with self._results_lock:
|
||||
results = self._pending_callbacks
|
||||
self._pending_callbacks = []
|
||||
|
||||
for result in results:
|
||||
result.callback(result.future)
|
||||
for closure in closures:
|
||||
closure()
|
||||
|
Loading…
Reference in New Issue
Block a user