Python 从线程返回值
如何让线程将元组或我选择的任何值返回到Python中的父级?在Python线程模块中,有一些与锁关联的条件对象。一个方法Python 从线程返回值,python,multithreading,python-multithreading,exit-code,Python,Multithreading,Python Multithreading,Exit Code,如何让线程将元组或我选择的任何值返回到Python中的父级?在Python线程模块中,有一些与锁关联的条件对象。一个方法acquire()将返回从基础方法返回的任何值。有关详细信息:我建议您在启动线程之前实例化一个,并将其作为线程的参数之一传递:在线程完成之前,它。将结果作为参数放入它接收到的队列中。家长可以随意.get或.get\u nowait它 在Python中,队列通常是安排线程同步和通信的最佳方式:它们本质上是线程安全的、消息传递工具——通常是组织多任务处理的最佳方式!) 另一种方法是
acquire()
将返回从基础方法返回的任何值。有关详细信息:我建议您在启动线程之前实例化一个,并将其作为线程的参数之一传递:在线程完成之前,它。将结果作为参数放入它接收到的队列中。家长可以随意.get
或.get\u nowait
它
在Python中,队列通常是安排线程同步和通信的最佳方式:它们本质上是线程安全的、消息传递工具——通常是组织多任务处理的最佳方式!) 另一种方法是向线程传递回调函数。这提供了一种简单、安全和灵活的方法,可以随时从新线程向父线程返回值
# 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()
如果调用join()等待线程完成,只需将结果附加到线程实例本身,然后在join()返回后从主线程检索它
另一方面,您没有告诉我们您打算如何发现线程已经完成并且结果可用。如果您已经有了这样做的方法,它可能会告诉您(以及我们,如果您告诉我们的话)获得结果的最佳方法。您应该将队列实例作为参数传递,然后您应该。将()返回对象放入队列中。您可以通过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()
我使用这个实现,它对我来说非常有用。我希望您这样做。使用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
POC:
您可以使用同步模块。
考虑使用已知的ID:/P>检查数据库中的用户信息。
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()
我很惊讶没有人提到你可以通过一个可变的:
>>> 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}
可能这有一些我不知道的主要问题。下面的包装器函数将包装一个现有函数并返回一个对象,该对象既指向线程(这样您就可以对其调用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()
给出返回值。基于jcomeau ictx的建议。我遇到的最简单的一个。这里的要求是从服务器上运行的三个不同进程中获取退出状态STAU,如果这三个进程都成功,则触发另一个脚本。这似乎很有效
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
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
对于简单的程序,上面的回答在我看来有点过分了。我希望采用可变方法:
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)
下面是一段实现多线程的代码
线程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)
导入线程
导入操作系统
导入队列
def任务1(数量,队列):
打印(“\n当前线程:{}”。格式(threading.Current_thread().name))
计数=0
sum1=0
当count时,我想出了一个简单的解决方案,在threading.thread
子类中使用闭包函数来获得线程的结果。不久之后,我还创建了PyPI包,以允许在项目()之间重用对下面相同代码的访问,并且由于该子类完全扩展了threading.Thread
类,因此您还可以设置threading.Thread
类上设置的任何属性:
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()
我认为这比绝大多数答案更容易理解,而且这种方法不需要额外的导入!我包括了time
和random
模块来模拟线程的行为,但在实际实现中并不需要它们
有关更多信息,请参阅更详细的说明(来自模块docstring)
下载并使用:
pip3 install -U save-thread-result # MacOS/Linux
pip install -U save-thread-result # Windows
python3 # MacOS/Linux
python # Windows
首先发布的问题是回调仍然在子线程中运行,而不是在原始线程中运行。@wilberforce您能解释一下它会导致什么问题吗?好的。例如,如果回调写入一个日志文件,则在线程运行时父线程也会写入该日志文件。由于回调在子线程中运行,因此存在两次写入同时发生并发生冲突的风险-您可能会得到乱码或交叉输出,或者如果日志框架进行一些内部簿记,则会发生崩溃。使用线程安全队列并让一个线程完成所有写入操作可以避免这种情况。这类问题可能很严重,因为它们不是确定性的-它们可能只在生产中出现,并且很难重现。您可以简单地将结果附加到线程实例本身。如何将线程实例传递给它运行的目标,以便目标可以将结果附加到此实例?Piotr Dobrogost,如果您没有为您的实例子类化线程,您可以只使用threading.current_Thread(),从您的目标可调用的末尾开始。我觉得这有点难看,但是Alex'a
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)