下面的函数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。


当前回答

我找到的大多数答案都很长,需要熟悉其他模块或高级python特性,除非他们已经熟悉答案所谈论的一切,否则会让人感到困惑。

简化方法的工作代码:

import threading

class ThreadWithResult(threading.Thread):
    def __init__(self, group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None):
        def function():
            self.result = target(*args, **kwargs)
        super().__init__(group=group, target=function, name=name, daemon=daemon)

示例代码:

import time, random


def function_to_thread(n):
    count = 0
    while count < 3:
            print(f'still running thread {n}')
            count +=1
            time.sleep(3)
    result = random.random()
    print(f'Return value of thread {n} should be: {result}')
    return result


def main():
    thread1 = ThreadWithResult(target=function_to_thread, args=(1,))
    thread2 = ThreadWithResult(target=function_to_thread, args=(2,))
    thread1.start()
    thread2.start()
    thread1.join()
    thread2.join()
    print(thread1.result)
    print(thread2.result)

main()

解释: 我想大大简化事情,所以我创建了一个ThreadWithResult类,并让它继承threading.Thread。__init__中的嵌套函数函数调用我们想要保存值的线程函数,并将该嵌套函数的结果保存为实例属性self。线程执行完成后的结果。

创建this的实例与创建threading.Thread的实例是相同的。将希望在新线程上运行的函数传递给目标参数,将函数可能需要的任何参数传递给args参数,将任何关键字参数传递给kwargs参数。

e.g.

my_thread = ThreadWithResult(target=my_function, args=(arg1, arg2, arg3))

我认为这比绝大多数答案更容易理解,而且这种方法不需要额外的导入!我加入了time和random模块来模拟线程的行为,但它们并不是实现最初问题中所要求的功能所必需的。

我知道我是在这个问题被问到很久之后才回答的,但我希望这能在未来帮助更多的人!


编辑:我创建了保存线程结果的PyPI包,允许你访问上面相同的代码,并在项目中重用它(GitHub代码在这里)。PyPI包完全扩展了线程。线程类,因此您可以设置在线程上设置的任何属性。线程在ThreadWithResult类!

上面的原始答案介绍了这个子类背后的主要思想,但要了解更多信息,请参阅这里更详细的解释(来自模块docstring)。

快速使用示例:

pip3 install -U save-thread-result     # MacOS/Linux
pip  install -U save-thread-result     # Windows

python3     # MacOS/Linux
python      # Windows
from save_thread_result import ThreadWithResult

# As of Release 0.0.3, you can also specify values for
#`group`, `name`, and `daemon` if you want to set those
# values manually.
thread = ThreadWithResult(
    target = my_function,
    args   = (my_function_arg1, my_function_arg2, ...)
    kwargs = {my_function_kwarg1: kwarg1_value, my_function_kwarg2: kwarg2_value, ...}
)

thread.start()
thread.join()
if getattr(thread, 'result', None):
    print(thread.result)
else:
    # thread.result attribute not set - something caused
    # the thread to terminate BEFORE the thread finished
    # executing the function passed in through the
    # `target` argument
    print('ERROR! Something went wrong while executing this thread, and the function you passed in did NOT complete!!')

# seeing help about the class and information about the threading.Thread super class methods and attributes available:
help(ThreadWithResult)

其他回答

定义你的目标 1)采取一个论点q 2)用q.put(foo)替换return foo的任何语句;返回

一个函数

def func(a):
    ans = a * a
    return ans

将成为

def func(a, q):
    ans = a * a
    q.put(ans)
    return

然后你就可以这样做了

from Queue import Queue
from threading import Thread

ans_q = Queue()
arg_tups = [(i, ans_q) for i in xrange(10)]

threads = [Thread(target=func, args=arg_tup) for arg_tup in arg_tups]
_ = [t.start() for t in threads]
_ = [t.join() for t in threads]
results = [q.get() for _ in xrange(len(threads))]

你可以使用函数装饰器/包装器来实现它,这样你就可以使用现有的函数作为目标,而不需要修改它们,但要遵循这个基本方案。

FWIW,多处理模块使用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.

在Python 3.2+中,stdlib concurrent。futures模块为线程提供了一个更高级别的API,包括将返回值或异常从工作线程传递回主线程:

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)

我知道这个线程是旧的....但我也遇到了同样的问题…如果你愿意使用thread.join()

import threading

class test:

    def __init__(self):
        self.msg=""

    def hello(self,bar):
        print('hello {}'.format(bar))
        self.msg="foo"


    def main(self):
        thread = threading.Thread(target=self.hello, args=('world!',))
        thread.start()
        thread.join()
        print(self.msg)

g=test()
g.main()

我发现做到这一点的最短和最简单的方法是利用Python类及其动态属性。您可以使用threading.current_thread()从派生线程的上下文中检索当前线程,并将返回值赋给一个属性。

import threading

def some_target_function():
    # Your code here.
    threading.current_thread().return_value = "Some return value."

your_thread = threading.Thread(target=some_target_function)
your_thread.start()
your_thread.join()

return_value = your_thread.return_value
print(return_value)