在Python中,我如何让一个线程返回一个元组或我选择的任何值给父线程?
在Python中,我如何让一个线程返回一个元组或我选择的任何值给父线程?
我建议在启动线程之前实例化一个Queue.Queue,并将其作为其中的一个参数传递给线程:在线程结束之前,它会将结果作为参数接收到的队列.put
。父进程可以随时使用.get
或.get_nowait
获取结果。
在Python中,队列通常是安排线程同步和通信的最佳方式:它们内在地支持线程安全的消息传递机制——是组织多任务处理的最佳方法!-)
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()
我使用了这个实现,对我来说非常好用。我希望你也能这样做。
response = queue.get()
会引发“Empty exception”并可能以已处理的异常终止。即使每次都成功,这也意味着每个线程都已完成,并且几乎没有实际的多线程发生。 - martineauqueue
将被填充的顺序之间的对应关系。我们能以某种顺序收集返回值吗? - Krishna Oza使用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
join()
方法返回调用方法的返回值,那就太好了...看起来它返回None
有点傻。 - ArtOfWarfare我很惊讶没有人提到您可以只传递一个可变对象:
>>> 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}
也许这有重大问题,我不知道。
另一种方法是将回调函数传递到线程中。这为从新线程向父级返回值提供了一种简单、安全和灵活的方式。
# 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()
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()
TypeError: square()接受1个位置参数,但实际给出了2个
。 - Mehdi RH对于简单的程序来说,以上的答案看起来有点过度设计了。我会采用可变的方法来使代码更加简洁:
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)
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
根据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
threading.Thread
,并将新的run()
方法简单地将结果存储为属性,例如self.ret = ...
。(更舒适的方法是Thread的子类来处理自定义目标函数的返回值/异常。确实,应该扩展threading.Thread
来提供这个功能 - 因为它会与旧行为“返回None”兼容。) - kxr