从线程返回值

时间:2009-12-11 06:00:58

标签: python multithreading python-multithreading exit-code

如何让一个线程将我的选择中的元组或任何值返回给Python中的父元素?

14 个答案:

答案 0 :(得分:59)

我建议你在启动线程之前实例化一个Queue.Queue,并将其作为线程的一个args传递:在线程完成之前,它.put将它作为参数接收到的队列上的结果。父母可随意.get.get_nowait

队列通常是在Python中安排线程同步和通信的最佳方式:它们本质上是线程安全的,消息传递工具 - 一般组织多任务的最佳方式! - )

答案 1 :(得分:12)

如果你正在调用join()来等待线程完成,你可以简单地将结果附加到Thread实例本身,然后在join()返回后从主线程中检索它。

另一方面,您没有告诉我们您打算如何发现线程已完成以及结果是否可用。如果你已经有办法做到这一点,它可能会指出你(以及我们,如果你告诉我们)最好的结果。

答案 2 :(得分:12)

您应该将Queue实例作为参数传递,然后将.put()返回对象放入队列中。您可以通过queue.get()收集返回值,无论您放置什么对象。

样品:

queue = Queue.Queue()
thread_ = threading.Thread(
                target=target_method,
                name="Thread1",
                args=[params, queue],
                )
thread_.start()
thread_.join()
queue.get()

def target_method(self, params, queue):
 """
 Some operations right here
 """
 your_return = "Whatever your object is"
 queue.put(your_return)

用于多个线程:

#Start all threads in thread pool
    for thread in pool:
        thread.start()
        response = queue.get()
        thread_results.append(response)

#Kill all threads
    for thread in pool:
        thread.join()

我使用这个实现,它对我很有用。我希望你这样做。

答案 3 :(得分:7)

使用 lambda 包装目标线程函数,并使用队列将其返回值传递回父线程。 (如果没有额外的队列参数,您的原始目标函数将保持不变。)

示例代码:

import threading
import queue
def dosomething(param):
    return param * 2
que = queue.Queue()
thr = threading.Thread(target = lambda q, arg : q.put(dosomething(arg)), args = (que, 2))
thr.start()
thr.join()
while not que.empty():
    print(que.get())

输出:

4

答案 4 :(得分:7)

我很惊讶没人提到你可以把它变成一个可变的:

>>> thread_return={'success': False}
>>> from threading import Thread
>>> def task(thread_return):
...  thread_return['success'] = True
... 
>>> Thread(target=task, args=(thread_return,)).start()
>>> thread_return
{'success': True}

也许这有一些我不知道的重大问题。

答案 5 :(得分:5)

另一种方法是将回调函数传递给线程。这提供了一种简单,安全且灵活的方式,可以随时从新线程向父项返回值。

# A sample implementation

import threading
import time

class MyThread(threading.Thread):
    def __init__(self, cb):
        threading.Thread.__init__(self)
        self.callback = cb

    def run(self):
        for i in range(10):
            self.callback(i)
            time.sleep(1)


# test

import sys

def count(x):
    print x
    sys.stdout.flush()

t = MyThread(count)
t.start()

答案 6 :(得分:3)

您可以使用已同步的queue模块 考虑您需要使用已知ID来检查数据库中的用户信息:

def check_infos(user_id, queue):
    result = send_data(user_id)
    queue.put(result)

现在您可以获得这样的数据:

import queue, threading
queued_request = queue.Queue()
check_infos_thread = threading.Thread(target=check_infos, args=(user_id, queued_request))
check_infos_thread.start()
final_result = queued_request.get()

答案 7 :(得分:2)

POC:

import random
import threading

class myThread( threading.Thread ):
    def __init__( self, arr ):
        threading.Thread.__init__( self )
        self.arr = arr
        self.ret = None

    def run( self ):
        self.myJob( self.arr )

    def join( self ):
        threading.Thread.join( self )
        return self.ret

    def myJob( self, arr ):
        self.ret = sorted( self.arr )
        return

#Call the main method if run from the command line.
if __name__ == '__main__':
    N = 100

    arr = [ random.randint( 0, 100 ) for x in range( N ) ]
    th = myThread( arr )
    th.start( )
    sortedArr = th.join( )

    print "arr2: ", sortedArr

答案 8 :(得分:1)

好吧,在Python线程模块中,有一些与锁相关联的条件对象。一个方法acquire()将返回从底层方法返回的任何值。有关详细信息:Python Condition Objects

答案 9 :(得分:1)

基于jcomeau_ictx的建议。我遇到的最简单的一个。这里的要求是从服务器上运行的三个不同进程获取退出状态状态,如果所有三个进程都成功,则触发另一个脚本。这似乎工作正常

  class myThread(threading.Thread):
        def __init__(self,threadID,pipePath,resDict):
            threading.Thread.__init__(self)
            self.threadID=threadID
            self.pipePath=pipePath
            self.resDict=resDict

        def run(self):
            print "Starting thread %s " % (self.threadID)
            if not os.path.exists(self.pipePath):
            os.mkfifo(self.pipePath)
            pipe_fd = os.open(self.pipePath, os.O_RDWR | os.O_NONBLOCK )
           with os.fdopen(pipe_fd) as pipe:
                while True:
                  try:
                     message =  pipe.read()
                     if message:
                        print "Received: '%s'" % message
                        self.resDict['success']=message
                        break
                     except:
                        pass

    tResSer={'success':'0'}
    tResWeb={'success':'0'}
    tResUisvc={'success':'0'}


    threads = []

    pipePathSer='/tmp/path1'
    pipePathWeb='/tmp/path2'
    pipePathUisvc='/tmp/path3'

    th1=myThread(1,pipePathSer,tResSer)
    th2=myThread(2,pipePathWeb,tResWeb)
    th3=myThread(3,pipePathUisvc,tResUisvc)

    th1.start()
    th2.start()
    th3.start()

    threads.append(th1)
    threads.append(th2)
    threads.append(th3)

    for t in threads:
        print t.join()

    print "Res: tResSer %s tResWeb %s tResUisvc %s" % (tResSer,tResWeb,tResUisvc)
    # The above statement prints updated values which can then be further processed

答案 10 :(得分:0)

以下包装器函数将包装一个现有函数并返回一个指向该线程的对象(以便您可以在其上调用start()join()等)以及访问/查看其最终的回报值。

def threadwrap(func,args,kwargs):
   class res(object): result=None
   def inner(*args,**kwargs): 
     res.result=func(*args,**kwargs)
   import threading
   t = threading.Thread(target=inner,args=args,kwargs=kwargs)
   res.thread=t
   return res

def myFun(v,debug=False):
  import time
  if debug: print "Debug mode ON"
  time.sleep(5)
  return v*2

x=threadwrap(myFun,[11],{"debug":True})
x.thread.start()
x.thread.join()
print x.result

它看起来不错,threading.Thread类似乎很容易扩展(*)这种功能,所以我想知道为什么它不存在。上述方法有缺陷吗?

(*)请注意,husanu对此问题的回答正是如此,将threading.Thread子类化,从而产生join()给出返回值的版本。​​

答案 11 :(得分:0)

对于简单的程序,以上答案对我来说似乎有点过头了。我会考虑使用可变方法:

class RetVal:
 def __init__(self):
   self.result = None


def threadfunc(retVal):
  retVal.result = "your return value"

retVal = RetVal()
thread = Thread(target = threadfunc, args = (retVal))

thread.start()
thread.join()
print(retVal.result)

答案 12 :(得分:0)

这里是实现多线程的代码。

线程1正在将数字从10加到20。 线程2正在将数字从21加到30。

最后,将输出返回到主程序,在该程序中可以执行最终加法。 (此程序未显示),但是您可以使用numpy调用。

import threading
import os
import queue

def task1(num, queue): 
    print("\n Current thread: {}".format(threading.current_thread().name)) 
    count = 0
    sum1 = 0
    while count <= 10:
        sum1 = sum1 + num
        num = num + 1
        count = count + 1
    print('\n'+str(sum1))
    queue.put(sum1)


if __name__ == "__main__":

    queue = queue.Queue()

    # print ID of current process 
    print("\n Process ID is: {}".format(os.getpid())) 

    # print name of main thread 
    print("\n Main thread is: {}".format(threading.main_thread().name)) 

    # creating threads 
    t1 = threading.Thread(target=task1, name='t1',args=[10,queue]) 
    t2 = threading.Thread(target=task1, name='t2',args=[21,queue])

    #Store thread names in a list
    pool = [t1,t2]

    #Used to store temporary values
    thread_results = []

    # starting threads
    #Start all threads in thread pool
    for thread in pool:
        thread.start()
        response = queue.get()
        thread_results.append(response)

    #Kill all threads
    for thread in pool:
        thread.join()

    print(thread_results)

答案 13 :(得分:0)

我想出了一个简单的解决方案来使用 threading.Thread 子类中的闭包函数来获取线程的结果。我还在不久之后创建了 save-thread-result PyPI 包,以允许访问下面的相同代码以在项目之间重用 (GitHub code is here),并且由于子类完全扩展了 threading.Thread 类,您可以设置您将在 threading.thread 类的 ThreadWithResult 上设置的任何属性:

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 threading, time, random

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)

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.result。

创建此实例与创建 threading.Thread 实例相同。将要在新线程上运行的函数传递给 target 参数,将函数可能需要的任何参数传递给 args 参数,并将任何关键字参数传递给 kwargs 参数。< /p>

例如

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

我认为这比绝大多数答案更容易理解,而且这种方法不需要额外的导入!我包含了 timerandom 模块来模拟线程的行为,但在实际实现中不需要它们。

有关更多信息,请参阅更详细的说明(来自模块文档字符串)here

下载 module from PyPI 并使用它:

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 hasattr(thread, 'result'):
    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
# in ThreadWithResult:
help(ThreadWithResult)

首次发布here