Rückgabewert aus Thread
-
19-09-2019 - |
Frage
Wie bekomme ich einen Thread, um ein Tupel oder einen Wert meiner Wahl an die Eltern in Python zurückzugeben?
Lösung
Ich schlage vor, Sie instanziieren a Queue.queue Bevor Sie den Thread starten und ihn als einer der Args des Threads übergeben: Bevor der Thread fertig ist .put
s das Ergebnis in der Warteschlange, die es als Argument erhielt. Der Elternteil kann .get
oder .get_nowait
es nach Belieben.
Warteschlangen sind im Allgemeinen der beste Weg, um die Synchronisation und Kommunikation von Threads in Python zu arrangieren: Sie sind intrinsisch fadensicher, Message-Passing-Fahrzeuge-der beste Weg, Multitasking im Allgemeinen zu organisieren!-)
Andere Tipps
Wenn Sie join () angerufen haben, um auf den Thread zu warten, können Sie das Ergebnis einfach an die Thread -Instanz selbst anschließen und dann nach dem Rückkehr der Juel () aus dem Haupt -Thread abrufen.
Andererseits sagen Sie uns nicht, wie Sie feststellen möchten, dass der Thread erledigt ist und dass das Ergebnis verfügbar ist. Wenn Sie dies bereits dazu haben, wird es Sie (und uns, wenn Sie es uns sagen) wahrscheinlich zum besten Weg, die Ergebnisse zu erzielen.
Sie sollten eine Warteschlange als Parameter übergeben, dann sollten Sie .put () Ihr Rückgabeobjekt in die Warteschlange. Sie können den Rückgabewert über Queue.get (), das Sie ausgeben, sammeln.
Probe:
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)
Verwendung für mehrere 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()
Ich benutze diese Implementierung und sie funktioniert hervorragend für mich. Ich wünschte du tust es.
Verwenden Lambda Um Ihre Ziel -Thread -Funktion zu wickeln und ihren Rückgabewert mit a an den übergeordneten Thread zurückzugeben Warteschlange. (Ihre ursprüngliche Zielfunktion bleibt unverändert ohne zusätzliche Warteschlangenparameter.)
Beispielcode:
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())
Ausgabe:
4
Ich bin überrascht, dass niemand erwähnt hat, dass Sie es einfach ein Veränderbar bestehen könnten:
>>> 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}
Vielleicht hat dies große Probleme, von denen ich nicht weiß.
Ein anderer Ansatz besteht darin, eine Rückruffunktion an den Thread zu übergeben. Dies gibt eine einfache, sichere und flexible Möglichkeit, den Elternteil jederzeit vom neuen Thread zu einem Wert zurückzugeben.
# 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()
Sie können synchronisiert verwenden Warteschlange Modul.
Bedenken Sie, dass Sie einen Benutzer -Infos aus der Datenbank mit einer bekannten ID überprüfen müssen:
def check_infos(user_id, queue):
result = send_data(user_id)
queue.put(result)
Jetzt können Sie Ihre Daten wie diese erhalten:
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()
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
Nun, im Python -Threading -Modul gibt es Konditionsobjekte, die Sperren zugeordnet sind. Eine Methode acquire()
Wird jeder Wert zurückgeben, der von der zugrunde liegenden Methode zurückgegeben wird. Für mehr Informationen: Python -Zustandsobjekte
Basierend auf dem Vorschlag von JComeau_ictx. Das einfachste, auf das ich gestoßen bin. Voraussetzung war hier, um den Exit -Status staus aus drei verschiedenen Prozessen auf dem Server zu erhalten und ein anderes Skript auszulösen, wenn alle drei erfolgreich sind. Dies scheint gut zu funktionieren
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
Die folgende Wrapper -Funktion wickelt eine vorhandene Funktion ein und gibt ein Objekt zurück, das beide auf den Thread verweist (damit Sie aufrufen können start()
,join()
, usw. darauf) sowie Zugriff/Anzeigen des letztendlichen Rückgabewerts.
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
Es sieht gut aus und die threading.Thread
Die Klasse scheint leicht (*) mit dieser Art von Funktionalität zu erweitern, also frage ich mich, warum es nicht schon da ist. Gibt es einen Fehler mit der obigen Methode?
(*) Beachten threading.Thread
was zu einer Version führt, wo join()
gibt den Rückgabewert.
Für einfache Programme sehen die oben genannten Antworten ein bisschen wie Overkill für mich aus. Ich würde den veränderlichen Ansatz nieren:
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)