From 592a1794234a6ce66a7bf7f96e9f7aae678f5dfb Mon Sep 17 00:00:00 2001 From: Paul McCarthy <pauld.mccarthy@gmail.com> Date: Mon, 23 May 2016 18:35:04 +0100 Subject: [PATCH] Ability to query async.idle queue. I feel like this module is duplicating functionality provided by the props.callqueue module. --- fsl/utils/async.py | 47 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/fsl/utils/async.py b/fsl/utils/async.py index 809599a3c..40393c7e3 100644 --- a/fsl/utils/async.py +++ b/fsl/utils/async.py @@ -29,6 +29,8 @@ warrant running in a separate thread. The :func:`wait` function is given one or more ``Thread`` instances, and a task to run. It waits until all the threads have finished, and then runs the task (via :func:`idle`). + +.. todo:: You could possibly use ``props.callqueue`` to drive the idle loop. """ @@ -134,34 +136,59 @@ loop. """ +_idleQueueSet = set() +"""A ``set`` containing the names of all named tasks which are +currently queued on the idle loop (see the ``name`` parameter to the +:func:`idle` function). +""" + + def _wxIdleLoop(ev): """Function which is called on ``wx.EVT_IDLE`` events. If there is a function on the :attr:`_idleQueue`, it is popped and called. """ + + global _idleQueue + global _idleQueueSet ev.Skip() try: - task, schedtime, timeout, args, kwargs = _idleQueue.get_nowait() + task, schedtime, name, timeout, args, kwargs = _idleQueue.get_nowait() except queue.Empty: return - name = getattr(task, '__name__', '<unknown>') now = time.time() elapsed = now - schedtime if timeout == 0 or (elapsed < timeout): - log.debug('Running function ({}) on wx idle loop'.format(name)) + log.debug('Running function ({}) on wx idle ' + 'loop'.format(getattr(task, '__name__', '<unknown>'))) task(*args, **kwargs) + if name is not None: + _idleQueueSet.discard(name) + if _idleQueue.qsize() > 0: ev.RequestMore() + + +def inIdle(taskName): + """Returns ``True`` if a task with the given name is queued on the + idle loop (or is currently running), ``False`` otherwise. + """ + global _idleQueueSet + return taskName in _idleQueueSet def idle(task, *args, **kwargs): """Run the given task on a ``wx.EVT_IDLE`` event. - :arg task: The task to run. + :arg task: The task to run. + + :arg name: Optional. If provided, must be provided as a keyword + argument. Specifies a name that can be used to query + the state of this task via the :func:`inIdle` function. :arg timeout: Optional. If provided, must be provided as a keyword argument. Specifies a time out, in seconds. If this @@ -175,10 +202,12 @@ def idle(task, *args, **kwargs): """ global _idleRegistered - global _idleTasks + global _idleQueue + global _idleQueueSet schedtime = time.time() timeout = kwargs.pop('timeout', 0) + name = kwargs.pop('name', None) if _haveWX(): import wx @@ -187,10 +216,12 @@ def idle(task, *args, **kwargs): wx.GetApp().Bind(wx.EVT_IDLE, _wxIdleLoop) _idleRegistered = True - name = getattr(task, '__name__', '<unknown>') - log.debug('Scheduling idle task ({}) on wx idle loop'.format(name)) + log.debug('Scheduling idle task ({}) on wx idle ' + 'loop'.format(getattr(task, '__name__', '<unknown>'))) - _idleQueue.put_nowait((task, schedtime, timeout, args, kwargs)) + _idleQueue.put_nowait((task, schedtime, name, timeout, args, kwargs)) + if name is not None: + _idleQueueSet.add(name) else: log.debug('Running idle task directly') -- GitLab