Files
bg/bg.py
2020-06-21 16:09:54 -07:00

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