Source code for dipy.viz.skyline.compute
"""Run callables in background threads with main-thread callback delivery."""
import queue
import threading
_callback_queue = queue.Queue()
[docs]
def run_async(func, callback, *args, **kwargs):
"""Execute ``func`` asynchronously in a background daemon thread.
Parameters
----------
func : callable
The function to execute in the background thread.
callback : callable
Function invoked as ``callback(result, exception)`` once ``func``
completes, where ``result`` is its return value and ``exception``
is any exception it raised, or None on success.
*args
Positional arguments passed to ``func``.
**kwargs
Keyword arguments passed to ``func``.
Notes
-----
``callback`` is never called from the worker thread. It is queued
together with the result and exception, and only runs when
:func:`process_async_callbacks` drains the queue on whichever thread
calls it (normally the main/UI thread). The worker thread is a daemon
thread, so it does not block interpreter shutdown.
"""
def worker():
result = None
exception = None
try:
result = func(*args, **kwargs)
except Exception as e: # noqa: BLE001
exception = e
finally:
# We do NOT execute the callback here!
# We package it up and send it to the main thread.
_callback_queue.put((callback, result, exception))
thread = threading.Thread(target=worker, daemon=True)
thread.start()
[docs]
def process_async_callbacks():
"""Drain the async task queue and run each callback on the calling thread.
Pair this with :func:`run_async` on the main/UI thread so background work
delivers results safely without blocking the worker thread.
"""
while not _callback_queue.empty():
callback, result, exception = _callback_queue.get_nowait()
callback(result, exception)