Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the return value from a thread in python?

The function foo below returns a string 'foo'. How can I get the value 'foo' which is returned from the thread's target?

from threading import Thread  def foo(bar):     print('hello {}'.format(bar))     return 'foo'  thread = Thread(target=foo, args=('world!',)) thread.start() return_value = thread.join() 

The "one obvious way to do it", shown above, doesn't work: thread.join() returned None.

like image 879
wim Avatar asked Aug 01 '11 03:08

wim


People also ask

How do you return a value from a thread?

How to Return Values From a Thread. A thread cannot return values directly. The start() method on a thread calls the run() method of the thread that executes our code in a new thread of execution. The run() method in turn may call a target function, if configured.

Can you return from a thread?

tl;dr a thread cannot return a value (at least not without a callback mechanism). You should reference a thread like an ordinary class and ask for the value.


2 Answers

One way I've seen is to pass a mutable object, such as a list or a dictionary, to the thread's constructor, along with a an index or other identifier of some sort. The thread can then store its results in its dedicated slot in that object. For example:

def foo(bar, result, index):     print 'hello {0}'.format(bar)     result[index] = "foo"  from threading import Thread  threads = [None] * 10 results = [None] * 10  for i in range(len(threads)):     threads[i] = Thread(target=foo, args=('world!', results, i))     threads[i].start()  # do some other stuff  for i in range(len(threads)):     threads[i].join()  print " ".join(results)  # what sound does a metasyntactic locomotive make? 

If you really want join() to return the return value of the called function, you can do this with a Thread subclass like the following:

from threading import Thread  def foo(bar):     print 'hello {0}'.format(bar)     return "foo"  class ThreadWithReturnValue(Thread):     def __init__(self, group=None, target=None, name=None,                  args=(), kwargs={}, Verbose=None):         Thread.__init__(self, group, target, name, args, kwargs, Verbose)         self._return = None     def run(self):         if self._Thread__target is not None:             self._return = self._Thread__target(*self._Thread__args,                                                 **self._Thread__kwargs)     def join(self):         Thread.join(self)         return self._return  twrv = ThreadWithReturnValue(target=foo, args=('world!',))  twrv.start() print twrv.join()   # prints foo 

That gets a little hairy because of some name mangling, and it accesses "private" data structures that are specific to Thread implementation... but it works.

For python3

class ThreadWithReturnValue(Thread):     def __init__(self, group=None, target=None, name=None,                  args=(), kwargs={}, Verbose=None):         Thread.__init__(self, group, target, name, args, kwargs)         self._return = None     def run(self):         print(type(self._target))         if self._target is not None:             self._return = self._target(*self._args,                                                 **self._kwargs)     def join(self, *args):         Thread.join(self, *args)         return self._return 
like image 95
kindall Avatar answered Oct 01 '22 05:10

kindall


FWIW, the multiprocessing module has a nice interface for this using the Pool class. And if you want to stick with threads rather than processes, you can just use the multiprocessing.pool.ThreadPool class as a drop-in replacement.

def foo(bar, baz):   print 'hello {0}'.format(bar)   return 'foo' + baz  from multiprocessing.pool import ThreadPool pool = ThreadPool(processes=1)  async_result = pool.apply_async(foo, ('world', 'foo')) # tuple of args for foo  # do some other stuff in the main process  return_val = async_result.get()  # get the return value from your function. 
like image 44
Jake Biesinger Avatar answered Oct 01 '22 04:10

Jake Biesinger