Tôi đã đánh cắp câu trả lời của kindall và làm sạch nó chỉ một chút.
Phần quan trọng là thêm * args và ** kwargs để tham gia () để xử lý thời gian chờ
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
CẬP NHẬT TRẢ LỜI DƯỚI ĐÂY
Đây là câu trả lời phổ biến nhất của tôi, vì vậy tôi quyết định cập nhật với mã sẽ chạy trên cả py2 và py3.
Ngoài ra, tôi thấy nhiều câu trả lời cho câu hỏi này cho thấy sự thiếu hiểu biết về Thread.join (). Một số hoàn toàn không xử lý các timeout
arg. Nhưng cũng có một trường hợp góc mà bạn cần lưu ý về các trường hợp khi bạn có (1) một hàm mục tiêu có thể trả về None
và (2) bạn cũng chuyển đối số timeout
để tham gia (). Vui lòng xem "KIỂM TRA 4" để hiểu trường hợp góc này.
Lớp ThreadWithReturn hoạt động với py2 và 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
Một số thử nghiệm mẫu được hiển thị dưới đây:
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))
Bạn có thể xác định trường hợp góc mà chúng ta có thể gặp phải với TEST 4 không?
Vấn đề là chúng tôi hy vọng giveMe () sẽ trả về Không (xem TEST 2), nhưng chúng tôi cũng mong tham gia () sẽ trả về Không nếu hết thời gian.
returned is None
có nghĩa là:
(1) đó là những gì giveMe () đã trả lại hoặc
(2) tham gia () đã hết thời gian
Ví dụ này là tầm thường vì chúng ta biết rằng giveMe () sẽ luôn trả về Không. Nhưng trong trường hợp thực tế (nơi mục tiêu có thể trả lại hợp pháp Không có gì hoặc điều gì khác), chúng tôi muốn kiểm tra rõ ràng những gì đã xảy ra.
Dưới đây là cách giải quyết trường hợp góc này:
# 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]
Thứ tự sẽ được duy trì và thoát khỏiwith
sẽ cho phép thu thập kết quả.[f.result() for f in futures]