简体   繁体   English

在Python线程中,我如何跟踪线程的完成?

[英]In Python threading, how I can I track a thread's completion?

I've a python program that spawns a number of threads. 我有一个python程序产生了许多线程。 These threads last anywhere between 2 seconds to 30 seconds. 这些线程持续2秒到30秒之间的任何时间。 In the main thread I want to track whenever each thread completes and print a message. 在主线程中,我想跟踪每个线程何时完成并打印消息。 If I just sequentially .join() all threads and the first thread lasts 30 seconds and others complete much sooner, I wouldn't be able to print a message sooner -- all messages will be printed after 30 seconds. 如果我只是顺序.join()所有线程和第一个线程持续30秒而其他线程更快完成,我将无法更快地打印消息 - 所有消息将在30秒后打印。

Basically I want to block until any thread completes. 基本上我想阻塞,直到任何线程完成。 As soon as a thread completes, print a message about it and go back to blocking if any other threads are still alive. 一旦线程完成,就打印一条关于它的消息,如果任何其他线程仍处于活动状态,则返回阻塞状态。 If all threads are done then exit program. 如果所有线程都已完成,则退出程序。

One way I could think of is to have a queue that is passed to all the threads and block on queue.get(). 我能想到的一种方法是将队列传递给所有线程并阻塞queue.get()。 Whenever a message is received from the queue, print it, check if any other threads are alive using threading.active_count() and if so, go back to blocking on queue.get(). 每当从队列接收到消息时,打印它,使用threading.active_count()检查是否有其他线程处于活动状态,如果是,则返回到queue.get()上的阻塞。 This would work but here all the threads need to follow the discipline of sending a message to the queue before terminating. 这可以工作,但是这里所有线程都需要遵循在终止之前向队列发送消息的规则。

I'm wonder if this is the conventional way of achieving this behavior or are there any other / better ways ? 我想知道这是否是实现这种行为的传统方式还是有其他/更好的方法?

需要使用Thread.is_alive()调用来检查Thread.is_alive()

Why not just have the threads themselves print a completion message, or call some other completion callback when done? 为什么不让线程本身打印完成消息,或者在完成后调用其他完成回调?

You can the just join these threads from your main program, so you'll see a bunch of completion messages and your program will terminate when they're all done, as required. 您可以直接从主程序join这些线程,这样您就会看到一堆完成消息,并且您的程序将在完成后根据需要终止。

Here's a quick and simple demonstration: 这是一个快速简单的演示:

#!/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!

Here's a variation on @detly's answer that lets you specify the messages from your main thread, instead of printing them from your target functions. 这是@ detly的答案的变体,它允许您指定主线程中的消息,而不是从目标函数中打印它们。 This creates a wrapper function which calls your target and then prints a message before terminating. 这将创建一个包装函数,用于调用目标,然后在终止之前输出消息。 You could modify this to perform any kind of standard cleanup after each thread completes. 您可以修改它以在每个线程完成后执行任何类型的标准清理。

#!/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"

What I would suggest is loop like this 我建议的是像这样循环

while len(threadSet) > 0:
    time.sleep(1)
    for thread in theadSet:
        if not thread.isAlive()
            print "Thread "+thread.getName()+" terminated"
            threadSet.remove(thread)

There is a 1 second sleep, so there will be a slight delay between the thread termination and the message being printed. 休眠时间为1秒,因此线程终止和正在打印的消息之间会有轻微的延迟。 If you can live with this delay, then I think this is a simpler solution than the one you proposed in your question. 如果你能忍受这种延迟,那么我认为这是一个比你在问题中提出的更简单的解决方案。

You can let the threads push their results into a threading.Queue . 你可以让线程将他们的结果推送到threading.Queue Have another thread wait on this queue and print the message as soon as a new item appears. 让另一个线程等待此队列,并在出现新项目时立即打印该消息。

I'm not sure I see the problem with using: threading.activeCount() 我不确定我看到使用的问题:threading.activeCount()

to track the number of threads that are still active? 跟踪仍处于活动状态的线程数?

Even if you don't know how many threads you're going to launch before starting it seems pretty easy to track. 即使您不知道在启动之前要启动多少个线程,它似乎很容易跟踪。 I usually generate thread collections via list comprehension then a simple comparison using activeCount to the list size can tell you how many have finished. 我通常通过列表理解生成线程集合,然后使用activeCount到列表大小的简单比较可以告诉您已经完成了多少。

See here: http://docs.python.org/library/threading.html 见这里: http//docs.python.org/library/threading.html

Alternately, once you have your thread objects you can just use the .isAlive method within the thread objects to check. 或者,一旦有了线程对象,就可以在线程对象中使用.isAlive方法来检查。

I just checked by throwing this into a multithread program I have and it looks fine: 我只是通过把它扔进一个多线程程序检查我看起来很好:

for thread in threadlist:
        print(thread.isAlive())

Gives me a list of True/False as the threads turn on and off. 当线程打开和关闭时,给我一个True / False列表。 So you should be able to do that and check for anything False in order to see if any thread is finished. 所以你应该能够这样做并检查任何错误,以便查看是否有任何线程完成。

I use a slightly different technique because of the nature of the threads I used in my application. 我使用稍微不同的技术,因为我在我的应用程序中使用的线程的性质。 To illustrate, this is a fragment of a test-strap program I wrote to scaffold a barrier class for my threading class: 为了说明,这是我编写的一个测试带程序的片段,用于为我的线程类构建一个barrier类:

   while threads:
        finished = set(threads) - set(threading.enumerate())
        while finished:
            ttt = finished.pop()
            threads.remove(ttt)
        time.sleep(0.5)

Why do I do it this way? 我为什么这样做? In my production code, I have a time limit, so the first line actually reads "while threads and time.time() < cutoff_time". 在我的生产代码中,我有一个时间限制,所以第一行实际上读取“while threads和time.time()<cutoff_time”。 If I reach the cut-off, I then have code to tell the threads to shut down. 如果我到达截止点,那么我会有代码告诉线程关闭。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM