74 lines
1.8 KiB
Python
74 lines
1.8 KiB
Python
#!python3
|
|
"""
|
|
bg.py
|
|
=====
|
|
Implement a simple parallel work class.
|
|
"""
|
|
# Uses low level threading.
|
|
import sys
|
|
import time
|
|
|
|
import _thread as _t
|
|
|
|
class NotReadyError(RuntimeError):
|
|
"Job is still running"
|
|
|
|
class Bg:
|
|
"""
|
|
Run a job in the background.
|
|
|
|
>>> job = Bg(func, arg1, arg2, ..., kwarg1=val1, kwarg2=...)
|
|
"""
|
|
_tid = None
|
|
_running = None
|
|
_result = None
|
|
_exc_info = None
|
|
|
|
# Start and finish timestamp of the job.
|
|
start = None
|
|
finish = None
|
|
|
|
def __init__(self, func, *args, **kwarg):
|
|
assert callable(func)
|
|
self._running = _t.allocate_lock()
|
|
|
|
## Create inner function to run in a thread.
|
|
def _job():
|
|
"Run requested callable in a thread"
|
|
self._running.acquire()
|
|
self.start = time.time()
|
|
try:
|
|
self._result = func(*args, **kwarg)
|
|
except:
|
|
self._exc_info = sys.exc_info()
|
|
finally:
|
|
self._running.release()
|
|
|
|
# Store the thread id in an instance variable.
|
|
self._tid = _t.start_new_thread(_job, ())
|
|
|
|
def is_running(self):
|
|
"Return True if the job is still running"
|
|
return self._running.locked()
|
|
|
|
def is_done(self):
|
|
"Return True if the job finished running"
|
|
return not self._running.locked()
|
|
|
|
def wait(self, _timeout=-1):
|
|
"Wait for the job to finish"
|
|
if self._running.acquire(True, _timeout):
|
|
self._running.release()
|
|
return self._result
|
|
raise NotReadyError("Exceeded the timeout")
|
|
|
|
@property
|
|
def result(self):
|
|
"Return the result if available, else raise NotReadyError"
|
|
if self._running.acquire(False):
|
|
self._running.release()
|
|
return self._result
|
|
raise NotReadyError("Result is not ready yet")
|
|
|
|
# Fin
|