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

转载 2013年12月05日 13:40:12

How can I access that return value 'foo' from the thread?

def foo(bar):
  print 'hello {0}'.format(bar)
  return 'foo'

from threading import Thread
t = Thread(target=foo, args=('world!',))
t.start()
x = t.join()
print x

The one obvious way to do it, above, seems to just return None in x.

share|improve this question
  add comment

5 Answers

up vote11down voteaccepted

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 themultiprocessing.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.
share|improve this answer
 
 
this is the best answer as it's non-intrusive –  Jayen yesterday
add comment

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 aThread 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.

share|improve this answer
 
 
thanks, i can see that that would be fine as a workaround, but it changes the function definition so that it doesn't really return anything. i wanted to know in my original case, where does that 'foo' actually go...? – wim Aug 2 '11 at 3:53 
 
@wim: Return values go somewhere only if you put them somewhere. Unfortunately, in the case of Thread, all that happens inside the class -- the default run() method does not store off the return value, so you lose it. You could write your own Thread subclass to handle this, though. I've taken a whack at it in my message. –  kindall Aug 3 '11 at 1:20
2  
cool, thanks for the example! i wonder why Thread was not implemented with handling a return value in the first place, it seems like an obvious enough thing to support. –  wim Aug 3 '11 at 1:28
add comment

Jake's answer is good, but if you don't want to use a threadpool (you don't know how many threads you'll need, but create them as needed) then a good way to transmit information between threads is the built-inQueue.Queue class, as it offers thread safety.

I created the following decorator to make it act in a similar fashion to the threadpool:

def threaded(f, daemon=False):
    import Queue

    def wrapped_f(q, *args, **kwargs):
        '''this function calls the decorated function and puts the 
        result in a queue'''
        ret = f(*args, **kwargs)
        q.put(ret)

    def wrap(*args, **kwargs):
        '''this is the function returned from the decorator. It fires off
        wrapped_f in a new thread and returns the thread object with
        the result queue attached'''

        q = Queue.Queue()

        t = threading.Thread(target=wrapped_f, args=(q,)+args, kwargs=kwargs)
        t.daemon = daemon
        t.start()
        t.result_queue = q        
        return t

    return wrap

Then you just use it as:

@threaded
def long_task(x):
    import time
    x = x + 5
    time.sleep(5)
    return x

# does not block, returns Thread object
y = long_task(10)
print y

# this blocks, waiting for the result
result = y.result_queue.get()
print result

The decorated function creates a new thread each time it's called and returns a Thread object that contains the queue that will receive the result.

share|improve this answer
 
 
I can't seem to get this to work; I get an error stating AttributeError: 'module' object has no attribute 'Lock' this appears to be emanating from the line y = long_task(10)... thoughts? – sadmicrowave Sep 13 at 2:26
 
The code doesn't explicitly use Lock, so the problem could be somewhere else in your code. You may want to post a new SO question about it –  bj0 Sep 14 at 4:18
add comment

join always return None, i think you should subclass Thread to handle return codes and so.

share|improve this answer
  add comment

My solution to the problem is to wrap the function and thread in a class. Does not require using pools,queues, or c type variable passing. It is also non blocking. You check status instead. See example of how to use it at end of code.

import threading

class ThreadWorker():
    '''
    The basic idea is given a function create an object.
    The object can then run the function in a thread.
    It provides a wrapper to start it,check its status,and get data out the function.
    '''
    def __init__(self,func):
        self.thread = None
        self.data = None
        self.func = self.save_data(func)

    def save_data(self,func):
        '''modify function to save its returned data'''
        def new_func(*args, **kwargs):
            self.data=func(*args, **kwargs)

        return new_func

    def start(self,params):
        self.data = None
        if self.thread is not None:
            if self.thread.isAlive():
                return 'running' #could raise exception here

        #unless thread exists and is alive start or restart it
        self.thread = threading.Thread(target=self.func,args=params)
        self.thread.start()
        return 'started'

    def status(self):
        if self.thread is None:
            return 'not_started'
        else:
            if self.thread.isAlive():
                return 'running'
            else:
                return 'finished'

    def get_results(self):
        if self.thread is None:
            return 'not_started' #could return exception
        else:
            if self.thread.isAlive():
                return 'running'
            else:
                return self.data

def add(x,y):
    return x +y

add_worker = ThreadWorker(add)
print add_worker.start((1,2,))
print add_worker.status()
print add_worker.get_results()
share|improve this answer
  add comment

spring aop(六)--代理调用机制

一.先看基于JDK的 1.从上面的Proxy.newProxyInstance(classLoader, proxiedInterfaces, this),这里的this就是指自身,一旦代理的方法被...
  • xiejx618
  • xiejx618
  • 2015年02月14日 12:30
  • 3435

zabbix监控软件的使用排错

在linux系统中,几乎所有运行的服务都会产生相对就的日志(log),所运行的程序在出错时都会有错误提示,即使没有任何提示也可以通过“echo $”来查看运行是否成功。使用zabbix已经有一段时间了...
  • zhangrandl
  • zhangrandl
  • 2014年08月01日 16:48
  • 13459

【代码积累】get set 属性访问器

工作前期,是在熟悉组里的代码,很基础的get set,却被我的同事们写出了许多花样,于是研究了一番。 一、属性访问器的基本写法   (1)自动属性 class Test { p...
  • u013047584
  • u013047584
  • 2016年08月06日 16:53
  • 767

基于注解的Spring AOP的配置和使用--转载

AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向切面编程。可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。...
  • z69183787
  • z69183787
  • 2016年06月30日 11:29
  • 363

20来行的Python拼写检查器

介绍了一个基于贝叶斯方法的Python写的20来行的拼写检查器
  • nirendao
  • nirendao
  • 2016年02月06日 13:08
  • 1070

Appium-Python-Client 源码剖析(一) driver 的元素查找方法

前言 Appium的实用方法都藏在Client的源码里,我尝试在这里剖析一下Client的源码,第一篇,我们直接从大家最关注的元素查找说起。 注意!对于driver和webelement实例,...
  • leonzhao2004
  • leonzhao2004
  • 2015年01月22日 13:23
  • 1992

新建maven项目,pom文件报错

在IDE中新建maven项目,pom文件报错! bug描述: Failure to transfer org.apache.maven.plugins:maven-surefire-plugi...
  • myNameIssls
  • myNameIssls
  • 2014年03月19日 11:56
  • 16736

zabbix监控软件的使用排错

在linux系统中,几乎所有运行的服务都会产生相对就的日志(log),所运行的程序在出错时都会有错误提示,即使没有任何提示也可以通过“echo $”来查看运行是否成功。使用zabbix已经有一段时间了...
  • hanzheng260561728
  • hanzheng260561728
  • 2016年05月27日 11:52
  • 2773

AOP源码解析(五)获取代理

确定了使用哪种代理方式后便可以进行代理的创建了 (1)JDK代理使用示例。 创建业务接口,业务对外提供的接口,包含着业务可以对外提供的功能。...
  • u012291108
  • u012291108
  • 2016年11月07日 23:59
  • 466

mybatis查询类型为int的字段,返回null的异常

原文链接:http://www.cnblogs.com/dingchenghong/archive/2012/07/04/2576504.html 项目中用mybatis3.x,用sql查询某个表类...
  • lee4037
  • lee4037
  • 2013年12月16日 23:40
  • 15991
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:how to get the return value from a thread in python?
举报原因:
原因补充:

(最多只允许输入30个字)