I recently started with python's threading module. After some trial and error I managed to get basic threading working using the following sample code given in most tutorials.
class SomeThread(threading.Thread): def __init__(self, count): threading.Thread.__init__(self) def run(self): print "Do something"
My problem is: I have a Class that has class variables and a function that I want to be run in a separate thread. However the function uses class variables and also writes to class variables. Like so:
class MyClass: somevar = 'someval' def func_to_be_threaded(self): # Uses other class functions # Do something with class variables
So how would I essentially 'put the thread class in MyClass'. So that if MyClass().func_to_threaded() is called it would run in a thread.
We defined a function to create a thread. Then we used the threading module to create a thread that invoked the function as its target. Then we used start() method to start the Python thread.
Threading speeds up program execution by allowing us to run parts of a program concurrently. So threading is a way that we can execute multiple pieces of code at the same time. There are two ways of creating threads in Python and those are; using a class or using a function.
Thread class can be extended to run code in another thread. This can be achieved by first extending the class, just like any other Python class. Then the run() function of the threading. Thread class must be overridden to contain the code that you wish to execute in another thread.
If I understand correctly you want to run a function in a separate thread? There are several ways to do that. But basically you wrap your function like this:
class MyClass: somevar = 'someval' def _func_to_be_threaded(self): # main body def func_to_be_threaded(self): threading.Thread(target=self._func_to_be_threaded).start()
It can be shortened with a decorator:
def threaded(fn): def wrapper(*args, **kwargs): threading.Thread(target=fn, args=args, kwargs=kwargs).start() return wrapper class MyClass: somevar = 'someval' @threaded def func_to_be_threaded(self): # main body
Edit Updated version with a handle:
def threaded(fn): def wrapper(*args, **kwargs): thread = threading.Thread(target=fn, args=args, kwargs=kwargs) thread.start() return thread return wrapper class MyClass: somevar = 'someval' @threaded def func_to_be_threaded(self): print 'xyz'
This can be used as follows:
>>> my_obj = MyClass() >>> handle = my_obj.func_to_be_threaded() >>> handle.join()
Now it is possible to extend it even more if you wish to return a value from the function. Consider this:
from threading import Thread from concurrent.futures import Future def call_with_future(fn, future, args, kwargs): try: result = fn(*args, **kwargs) future.set_result(result) except Exception as exc: future.set_exception(exc) def threaded(fn): def wrapper(*args, **kwargs): future = Future() Thread(target=call_with_future, args=(fn, future, args, kwargs)).start() return future return wrapper class MyClass: @threaded def get_my_value(self): return 1 >>> my_obj = MyClass() >>> fut = my_obj.get_my_value() # this will run in a separate thread >>> fut.result() # will block until result is computed 1
If you don't have concurrent.futures.Future class (because for example you are using Python2.7 or older) then you can use this simplified implementation:
from threading import Event class Future(object): def __init__(self): self._ev = Event() def set_result(self, result): self._result = result self._ev.set() def set_exception(self, exc): self._exc = exc self._ev.set() def result(self): self._ev.wait() if hasattr(self, '_exc'): raise self._exc return self._result
I advice reading through concurrent.futures module since it has a lot of neat tools. For example Thread
class should be replaced with a ThreadPoolExecutor
instance to limit concurrency (e.g. you don't want to spam 10k threads). Also with ThreadPoolExecutor
the code is even simplier (and less error prone):
from concurrent.futures import ThreadPoolExecutor tp = ThreadPoolExecutor(10) # max 10 threads def threaded(fn): def wrapper(*args, **kwargs): return tp.submit(fn, *args, **kwargs) # returns Future object return wrapper
Just remember you have to tp.shutdown()
after you're done with all parallel work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With