等待列表中的特定线程

时间:2018-07-26 20:47:22

标签: python python-3.x multithreading events

我有3个线程:A,B和C。

它们在 threads 列表中,并与

同时触发
A.start()
B.start()
C.start()

我不知道哪个线程会先完成。

我需要在每个线程结束时触发动作,就像这样:

for t in threads:
    t.join()
    action()

此代码在这种情况下不正确,因为:我必须在检查B之前等待第一个A线程完成,然后等待B修改以检查C等。

如何以独立的方式等待每个线程,就像“ .join()”是事件一样?

2 个答案:

答案 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