Ich habe die Antwort von kindall gestohlen und sie nur ein wenig aufgeräumt.
Der Schlüsselteil ist das Hinzufügen von * args und ** kwargs zu join (), um das Timeout zu behandeln
class threadWithReturn(Thread):
def __init__(self, *args, **kwargs):
super(threadWithReturn, self).__init__(*args, **kwargs)
self._return = None
def run(self):
if self._Thread__target is not None:
self._return = self._Thread__target(*self._Thread__args, **self._Thread__kwargs)
def join(self, *args, **kwargs):
super(threadWithReturn, self).join(*args, **kwargs)
return self._return
AKTUALISIERTE ANTWORT UNTEN
Dies ist meine am häufigsten gewählte Antwort, daher habe ich beschlossen, mit Code zu aktualisieren, der sowohl auf py2 als auch auf py3 ausgeführt wird.
Außerdem sehe ich viele Antworten auf diese Frage, die ein Unverständnis in Bezug auf Thread.join () zeigen. Einige können das timeoutArgument überhaupt nicht verarbeiten. Es gibt aber auch einen Eckfall, den Sie in Bezug auf Fälle kennen sollten, in denen Sie (1) eine Zielfunktion haben, die zurückkehren kann, Noneund (2) Sie auch das timeoutArgument an join () übergeben. Bitte lesen Sie "TEST 4", um diesen Eckfall zu verstehen.
ThreadWithReturn-Klasse, die mit py2 und py3 funktioniert:
import sys
from threading import Thread
from builtins import super # https://stackoverflow.com/a/30159479
if sys.version_info >= (3, 0):
_thread_target_key = '_target'
_thread_args_key = '_args'
_thread_kwargs_key = '_kwargs'
else:
_thread_target_key = '_Thread__target'
_thread_args_key = '_Thread__args'
_thread_kwargs_key = '_Thread__kwargs'
class ThreadWithReturn(Thread):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._return = None
def run(self):
target = getattr(self, _thread_target_key)
if not target is None:
self._return = target(
*getattr(self, _thread_args_key),
**getattr(self, _thread_kwargs_key)
)
def join(self, *args, **kwargs):
super().join(*args, **kwargs)
return self._return
Einige Beispieltests sind unten gezeigt:
import time, random
# TEST TARGET FUNCTION
def giveMe(arg, seconds=None):
if not seconds is None:
time.sleep(seconds)
return arg
# TEST 1
my_thread = ThreadWithReturn(target=giveMe, args=('stringy',))
my_thread.start()
returned = my_thread.join()
# (returned == 'stringy')
# TEST 2
my_thread = ThreadWithReturn(target=giveMe, args=(None,))
my_thread.start()
returned = my_thread.join()
# (returned is None)
# TEST 3
my_thread = ThreadWithReturn(target=giveMe, args=('stringy',), kwargs={'seconds': 5})
my_thread.start()
returned = my_thread.join(timeout=2)
# (returned is None) # because join() timed out before giveMe() finished
# TEST 4
my_thread = ThreadWithReturn(target=giveMe, args=(None,), kwargs={'seconds': 5})
my_thread.start()
returned = my_thread.join(timeout=random.randint(1, 10))
Können Sie den Eckfall identifizieren, auf den wir möglicherweise bei TEST 4 stoßen?
Das Problem ist, dass wir erwarten, dass giveMe () None zurückgibt (siehe TEST 2), aber wir erwarten auch, dass join () None zurückgibt, wenn das Zeitlimit überschritten wird.
returned is None bedeutet entweder:
(1) das hat giveMe () zurückgegeben, oder
(2) Zeitüberschreitung bei join ()
Dieses Beispiel ist trivial, da wir wissen, dass giveMe () immer None zurückgibt. In der realen Welt (in der das Ziel möglicherweise keine oder etwas anderes zurückgibt) möchten wir jedoch explizit überprüfen, was passiert ist.
Im Folgenden erfahren Sie, wie Sie diesen Eckfall angehen können:
# TEST 4
my_thread = ThreadWithReturn(target=giveMe, args=(None,), kwargs={'seconds': 5})
my_thread.start()
returned = my_thread.join(timeout=random.randint(1, 10))
if my_thread.isAlive():
# returned is None because join() timed out
# this also means that giveMe() is still running in the background
pass
# handle this based on your app's logic
else:
# join() is finished, and so is giveMe()
# BUT we could also be in a race condition, so we need to update returned, just in case
returned = my_thread.join()
futures = [executor.submit(foo, param) for param in param_list]Die Reihenfolge wird beibehalten, und das Verlassen der Reihenfolgewithermöglicht die Ergebniserfassung.[f.result() for f in futures]