我有一个python程序产生了许多线程。这些线程持续2秒到30秒之间的任何时间。在主线程中,我想跟踪每个线程何时完成并打印消息。如果我只是顺序.join()所有线程和第一个线程持续30秒而其他线程更快完成,我将无法更快地打印消息 - 所有消息将在30秒后打印。
基本上我想阻止,直到任何线程完成。一旦线程完成,就打印一条关于它的消息,如果任何其他线程仍处于活动状态,则返回阻塞状态。如果所有线程都已完成,则退出程序。
我能想到的一种方法是将队列传递给所有线程并阻塞queue.get()。每当从队列接收到消息时,打印它,使用threading.active_count()检查是否有其他线程处于活动状态,如果是,则返回到queue.get()上的阻塞。这可以工作,但是这里所有线程都需要遵循在终止之前向队列发送消息的规则。
我想知道这是否是实现此行为的传统方式,还是有其他/更好的方式?
答案 0 :(得分:5)
需要使用Thread.is_alive()
调用来检查线程。
答案 1 :(得分:4)
为什么不让线程本身打印完成消息,或者在完成后调用其他完成回调?
您可以从主程序中找到join
这些线程,这样您就会看到一堆完成消息,并且当您完成所有操作后,您的程序将会终止。
这是一个快速而简单的演示:
#!/usr/bin/python
import threading
import time
def really_simple_callback(message):
"""
This is a really simple callback. `sys.stdout` already has a lock built-in,
so this is fine to do.
"""
print message
def threaded_target(sleeptime, callback):
"""
Target for the threads: sleep and call back with completion message.
"""
time.sleep(sleeptime)
callback("%s completed!" % threading.current_thread())
if __name__ == '__main__':
# Keep track of the threads we create
threads = []
# callback_when_done is effectively a function
callback_when_done = really_simple_callback
for idx in xrange(0, 10):
threads.append(
threading.Thread(
target=threaded_target,
name="Thread #%d" % idx,
args=(10 - idx, callback_when_done)
)
)
[t.start() for t in threads]
[t.join() for t in threads]
# Note that thread #0 runs for the longest, but we'll see its message first!
答案 2 :(得分:3)
这是@ detly的答案的变体,它允许您指定主线程中的消息,而不是从目标函数中打印它们。这将创建一个包装函数,用于调用目标,然后在终止之前输出消息。您可以修改它以在每个线程完成后执行任何类型的标准清理。
#!/usr/bin/python
import threading
import time
def target1():
time.sleep(0.1)
print "target1 running"
time.sleep(4)
def target2():
time.sleep(0.1)
print "target2 running"
time.sleep(2)
def launch_thread_with_message(target, message, args=[], kwargs={}):
def target_with_msg(*args, **kwargs):
target(*args, **kwargs)
print message
thread = threading.Thread(target=target_with_msg, args=args, kwargs=kwargs)
thread.start()
return thread
if __name__ == '__main__':
thread1 = launch_thread_with_message(target1, "finished target1")
thread2 = launch_thread_with_message(target2, "finished target2")
print "main: launched all threads"
thread1.join()
thread2.join()
print "main: finished all threads"
答案 3 :(得分:2)
我建议的是像这样循环
while len(threadSet) > 0:
time.sleep(1)
for thread in theadSet:
if not thread.isAlive()
print "Thread "+thread.getName()+" terminated"
threadSet.remove(thread)
休眠时间为1秒,因此线程终止和正在打印的消息之间会有轻微的延迟。如果你能忍受这种延迟,那么我认为这是一个比你提出的问题更简单的解决方案。
答案 4 :(得分:1)
您可以让线程将结果推送到threading.Queue
。让另一个线程等待此队列,并在出现新项目时立即打印该消息。
答案 5 :(得分:0)
我不确定我看到使用的问题: threading.activeCount()
跟踪仍处于活动状态的线程数?
即使您不知道在启动之前要启动的线程数似乎也很容易跟踪。我通常通过列表理解生成线程集合,然后使用activeCount到列表大小的简单比较可以告诉你有多少已经完成。
见这里:http://docs.python.org/library/threading.html
或者,一旦有了线程对象,就可以在线程对象中使用.isAlive方法进行检查。
我只是通过把它扔进我的多线程程序来检查它看起来很好:
for thread in threadlist:
print(thread.isAlive())
当线程打开和关闭时,给我一个True / False列表。所以你应该能够做到并检查任何错误,以便查看是否有任何线程完成。
答案 6 :(得分:0)
由于我在应用程序中使用的线程的性质,我使用了稍微不同的技术。为了说明,这是我编写的一个测试带程序的一个片段,用于为我的线程类构建一个barrier类:
while threads:
finished = set(threads) - set(threading.enumerate())
while finished:
ttt = finished.pop()
threads.remove(ttt)
time.sleep(0.5)
为什么我这样做?在我的生产代码中,我有一个时间限制,所以第一行实际上读取“while threads and time.time()< cutoff_time”。如果我到达截止点,那么我会有代码告诉线程关闭。