ฉันขโมยคำตอบของทุกคนและทำความสะอาดมันเล็กน้อย
ส่วนสำคัญคือการเพิ่ม * args และ ** kwargs เพื่อเข้าร่วม () เพื่อจัดการการหมดเวลา
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
ปรับปรุงคำตอบด้านล่าง
นี่คือคำตอบที่ได้รับความนิยมสูงสุดของฉันดังนั้นฉันตัดสินใจที่จะอัปเดตด้วยรหัสที่จะทำงานทั้ง py2 และ py3
นอกจากนี้ฉันเห็นคำตอบมากมายสำหรับคำถามนี้ที่แสดงความไม่เข้าใจเกี่ยวกับ Thread.join () บางคนล้มเหลวในการจัดการtimeout
หาเรื่องอย่างสมบูรณ์ แต่ก็มีกรณีมุมที่คุณควรทราบเกี่ยวกับอินสแตนซ์เมื่อคุณมี (1) ฟังก์ชั่นเป้าหมายที่สามารถส่งคืนNone
และ (2) คุณยังผ่านtimeout
ARG เพื่อเข้าร่วม () โปรดดู "การทดสอบ 4" เพื่อทำความเข้าใจกรณีมุมนี้
คลาส ThreadWithReturn ที่ทำงานกับ py2 และ 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
ตัวอย่างการทดสอบมีดังนี้:
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))
คุณช่วยระบุมุมที่เราอาจเผชิญกับ TEST 4 ได้หรือไม่?
ปัญหาคือเราคาดหวังว่า giveMe () จะคืนค่า None (ดูทดสอบ 2) แต่เราก็คาดหวังให้ join () เพื่อคืนค่า None หากหมดเวลา
returned is None
หมายถึงอย่างใดอย่างหนึ่ง:
(1) นั่นคือสิ่งที่ giveMe () กลับมาหรือ
(2) เข้าร่วม () หมดเวลา
ตัวอย่างนี้เล็กน้อยเนื่องจากเรารู้ว่า giveMe () จะคืนค่า None เสมอ แต่ในโลกแห่งความเป็นจริง (ซึ่งเป้าหมายอาจส่งคืน None หรืออย่างอื่นอย่างถูกกฎหมาย) เราต้องการตรวจสอบสิ่งที่เกิดขึ้นอย่างชัดเจน
ด้านล่างเป็นวิธีการระบุมุมตัวพิมพ์นี้:
# 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]
คำสั่งซื้อจะได้รับการเก็บรักษาและออกจากwith
จะอนุญาตให้รวบรวมผลลัพธ์[f.result() for f in futures]