如何获取线程的返回值?

647 投票
29 回答
722539 浏览
提问于 2025-04-16 22:38

下面这个函数 foo 会返回一个字符串 'foo'。我该怎么才能得到这个线程返回的值 'foo' 呢?

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()

上面提到的“一个明显的做法”是行不通的:调用 thread.join() 后返回的是 None

29 个回答

368

顺便说一下,multiprocessing模块提供了一个很不错的接口,可以使用Pool类来实现这个功能。如果你想继续使用线程而不是进程,可以直接用multiprocessing.pool.ThreadPool类来替代。

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

我见过一种方法,就是把一个可变对象,比如列表或字典,传给线程的构造函数,同时还要传一个索引或者其他标识符。这样,线程就可以把它的结果存储在这个对象的专用位置里。例如:

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?

如果你真的想让 join() 返回被调用函数的返回值,你可以通过创建一个 Thread 的子类来实现,像下面这样:

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

这有点复杂,因为涉及到一些名称处理,而且它访问了特定于 Thread 实现的“私有”数据结构……不过它是可行的。

对于 Python 3:

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):
        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
311

在Python 3.2及以上版本中,标准库中的 concurrent.futures 模块提供了一种更高级的接口来使用 threading,这意味着你可以更方便地将工作线程的返回值或异常传回主线程:

import concurrent.futures

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

with concurrent.futures.ThreadPoolExecutor() as executor:
    future = executor.submit(foo, 'world!')
    return_value = future.result()
    print(return_value)

撰写回答