Although Python's thread syntax is nicer than in many languages, it can still be a pain if all one wants to do is run a time-consuming function in a separate thread, while allowing the main thread to continue uninterrupted. A Future provides a legible and intuitive way to achieve such an end.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
from threading import * import copy class Future: def __init__(self,func,*param): # Constructor self.__done=0 self.__result=None self.__status='working' self.__C=Condition() # Notify on this Condition when result is ready # Run the actual function in a separate thread self.__T=Thread(target=self.Wrapper,args=(func,param)) self.__T.setName("FutureThread") self.__T.start() def __repr__(self): return '<Future at '+hex(id(self))+':'+self.__status+'>' def __call__(self): self.__C.acquire() while self.__done==0: self.__C.wait() self.__C.release() # We deepcopy __result to prevent accidental tampering with it. a=copy.deepcopy(self.__result) return a def Wrapper(self, func, param): # Run the actual function, and let us housekeep around it self.__C.acquire() try: self.__result=func(*param) except: self.__result="Exception raised within Future" self.__done=1 self.__status=`self.__result` self.__C.notify() self.__C.release()
To run a function in a separate thread, simply put it in a Future:
>>> A=Future(longRunningFunction, arg1, arg2 ...)
It will continue on its merry way until you need the result of your function. You can read the result by calling the Future like a function, for example:
>>> print A()
If the Future has completed executing, the call returns immediately. If it is still running, then the call blocks until the function completes. The result of the function is stored in the Future, so subsequent calls to it return immediately.
A few caveats: Since one wouldn't expect to be able to change the result of a function, Futures are not meant to be mutable. This is enforced by requiring the Future to be "called", rather than directly reading __result. If desired, stronger enforcement of this rule can be achieved by playing with __getattr__ and __setattr__.
The Future only runs the function once, no matter how many times you read it. You will have to re-create the Future if you want to re-run your function; for example, if the function is sensitive to the time of day.
For more information on Futures, and other useful parallel programming constructs, read Gregory V. Wilson's _Practical Parallel Programming_.