Saya mencuri jawaban baik hati dan membersihkannya sedikit saja.
Bagian kuncinya adalah menambahkan * args dan ** kwargs untuk bergabung () untuk menangani batas waktu
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
JAWABAN DIPERBARUI DI BAWAH INI
Ini adalah jawaban saya yang paling populer, jadi saya memutuskan untuk memperbarui dengan kode yang akan berjalan pada py2 dan py3.
Selain itu, saya melihat banyak jawaban untuk pertanyaan ini yang menunjukkan kurangnya pemahaman tentang Thread.join (). Beberapa gagal menangani timeout
arg. Tetapi ada juga kasus sudut yang harus Anda ketahui tentang instance ketika Anda memiliki (1) fungsi target yang dapat kembali None
dan (2) Anda juga memberikan timeout
argumen untuk bergabung (). Silakan lihat "TEST 4" untuk memahami kasus sudut ini.
Kelas ThreadWithReturn yang bekerja dengan py2 dan py3:
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
Beberapa tes sampel ditunjukkan di bawah ini:
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))
Bisakah Anda mengidentifikasi kasus sudut yang mungkin kita temui dengan TEST 4?
Masalahnya adalah kita mengharapkan giveMe () mengembalikan None (lihat TEST 2), tetapi kami juga berharap join () mengembalikan None jika itu habis.
returned is None
berarti:
(1) itulah yang mengembalikan giveMe (), atau
(2) gabung () habis
Contoh ini sepele karena kita tahu bahwa giveMe () akan selalu mengembalikan None. Tetapi dalam contoh dunia nyata (di mana target dapat secara sah mengembalikan Tidak ada atau sesuatu yang lain) kami ingin secara eksplisit memeriksa apa yang terjadi.
Di bawah ini adalah cara mengatasi casing sudut ini:
# 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]
Pesanan akan dipertahankan, dan keluar dariwith
akan memungkinkan pengumpulan hasil.[f.result() for f in futures]