我有3个线程:A,B和C。
它们在 threads 列表中,并与
同时触发A.start()
B.start()
C.start()
我不知道哪个线程会先完成。
我需要在每个线程结束时触发动作,就像这样:
for t in threads:
t.join()
action()
此代码在这种情况下不正确,因为:我必须在检查B之前等待第一个A线程完成,然后等待B修改以检查C等。
如何以独立的方式等待每个线程,就像“ .join()”是事件一样?
答案 0 :(得分:0)
您正在寻找的是一种等待线程组的方法,而Python的API不提供这种方法。因此,您必须对其进行仿真。
最简单但效率最低的方法只是忙于轮询线程:
while threads:
for thread in threads:
thread.join(timeout=0.1)
if not thread.is_alive():
action(thread)
threads.remove(thread)
break
time.sleep(0.1)
更好的解决方案是使用一个同步对象,所有线程都可以在退出之前立即发出信号。您可以使用简单的Event
:
while threads:
evt.wait()
evt.clear()
for thread in threads:
if not thread.is_alive():
thread.join()
action(thread)
threads.remove(thread)
break
但是,这与任何自重置事件都具有相同的潜在比赛条件:您可能会错过触发器。在某些情况下,您可以研究所有细节并确定比赛不会造成任何伤害。如果没有,则必须使用稍微复杂一些的东西,例如Condition
。
或者您可以跳到更高的级别并使用Queue
,线程可以在退出前只q.put(self)
。然后,主线程很容易就正确了:
while threads:
thread = q.get()
thread.join()
action(thread)
threads.remove(thread)
但是值得考虑的是,您实际上是否需要3个线程函数,或者需要在池或执行程序上运行的3个任务函数,甚至需要3个不同的args的任务函数。
例如,对于具有3组args的单个函数,很难比这更简单:
with multiprocessing.dummy.Pool(3) as pool:
for result in pool.imap_unordered(func, [arg1, arg2, arg3]):
action(result)
或者,对于3个功能:
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as ex:
fs = [ex.submit(func) for func in funcs]
for f in concurrent.futures.as_completed(fs):
action(f.result())
或者您甚至可以将action
附加到期货上:
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as ex:
for func in funcs:
ex.submit(func).add_done_callback(action)
答案 1 :(得分:0)
您的问题遗漏了许多细节,所以我猜到了并提出了以下方法来证明一种方法:
from random import random
from threading import Thread
from time import sleep
def callback(name):
print('thread {} finished'.format(name))
A = Thread(target=lambda: sleep(random()))
B = Thread(target=lambda: sleep(random()))
C = Thread(target=lambda: sleep(random()))
A.start()
B.start()
C.start()
threads = {'A': A, 'B': B, 'C': C}
while threads:
for name, thread in sorted(threads.items()):
if not thread.is_alive():
callback(name)
threads.pop(name)
break
print('done')
典型输出:
thread C finished
thread A finished
thread B finished
done