[gnome-music/wip/mschraal/file-exists-async: 29/30] asyncqueue: Dispatch tasks on a timer




commit f00e084acc2edbea53d3717eee8d099ee8fea441
Author: Marinus Schraal <mschraal gnome org>
Date:   Sat Sep 4 23:09:00 2021 +0200

    asyncqueue: Dispatch tasks on a timer
    
    Previously Asyncqueue used a recursive call to queue more tasks, in rare
    cases this could lead to hitting the Python recursion depth.
    
    To avoid this, use timeout based scheduling.

 gnomemusic/asyncqueue.py | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)
---
diff --git a/gnomemusic/asyncqueue.py b/gnomemusic/asyncqueue.py
index 125b2145f..bb8710566 100644
--- a/gnomemusic/asyncqueue.py
+++ b/gnomemusic/asyncqueue.py
@@ -25,7 +25,7 @@
 from typing import Any, Dict, Optional, Tuple
 import time
 
-from gi.repository import GObject
+from gi.repository import GObject, GLib
 
 from gnomemusic.musiclogger import MusicLogger
 
@@ -60,6 +60,8 @@ class AsyncQueue(GObject.GObject):
         self._max_async = 4
         self._queue_name = queue_name if queue_name else self
 
+        self._timeout_id = 0
+
     def queue(self, *args: Any) -> None:
         """Queue an async call
 
@@ -68,16 +70,17 @@ class AsyncQueue(GObject.GObject):
             to the `start` call of the given class.
             See the class doc for more information.
         """
-        async_obj = args[0]
-        async_obj_id = id(async_obj)
-        result_id = 0
+        async_obj_id = id(args[0])
 
         if (async_obj_id not in self._async_pool
                 and async_obj_id not in self._async_active_pool):
             self._async_pool[async_obj_id] = (args)
-        else:
-            return
 
+        if self._timeout_id == 0:
+            self_timeout_id = GLib.timeout_add(250, self._dispatch)
+
+    def _dispatch(self) -> bool:
+        result_id = 0
         tick = time.time()
 
         def on_async_finished(obj, *signal_args):
@@ -97,10 +100,15 @@ class AsyncQueue(GObject.GObject):
                 args = self._async_pool.pop(key)
                 self.queue(*args)
 
-        if len(self._async_active_pool) < self._max_async:
-            async_task_args = self._async_pool.pop(async_obj_id)
+        if len(self._async_pool) == 0:
+            self._timeout_id = 0
+            return GLib.SOURCE_REMOVE
+        elif len(self._async_active_pool) < self._max_async:
+            async_obj_id, async_task_args = self._async_pool.popitem()
             async_obj = async_task_args[0]
             self._async_active_pool[async_obj_id] = async_task_args
 
             result_id = async_obj.connect("finished", on_async_finished)
             async_obj.start(*async_task_args[1:])
+
+        return GLib.SOURCE_CONTINUE


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]