【问题标题】:In Python threading, how I can I track a thread's completion?在 Python 线程中,我如何跟踪线程的完成情况?
【发布时间】:2016-09-08 22:55:18
【问题描述】:

我有一个生成多个线程的 python 程序。这些线程持续 2 秒到 30 秒之间的任何时间。在主线程中,我想跟踪每个线程何时完成并打印一条消息。如果我只是按顺序 .join() 所有线程并且第一个线程持续 30 秒而其他线程更快地完成,我将无法更快地打印消息 - 所有消息都将在 30 秒后打印。

基本上我想阻塞直到 any 线程完成。一旦线程完成,打印一条关于它的消息,如果任何其他线程仍然存在,则返回阻塞。如果所有线程都完成,则退出程序。

我能想到的一种方法是让一个队列传递给所有线程并阻塞在 queue.get() 上。每当从队列接收到消息时,打印它,使用 threading.active_count() 检查是否有其他线程处于活动状态,如果是,则返回到 queue.get() 上的阻塞。这会起作用,但这里所有线程都需要遵循在终止之前向队列发送消息的规则。

我想知道这是实现这种行为的传统方式还是有其他/更好的方式?

【问题讨论】:

    标签: python multithreading


    【解决方案1】:

    这是@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"
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        为什么不让线程自己打印完成消息,或者在完成后调用其他完成回调?

        您可以在主程序中只使用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!
        

        【讨论】:

          【解决方案4】:

          我的建议是这样的循环

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

          有 1 秒的休眠,所以在线程终止和打印消息之间会有一点延迟。如果您可以忍受这种延迟,那么我认为这比您在问题中提出的解决方案更简单。

          【讨论】:

            【解决方案5】:

            您可以让线程将其结果推送到threading.Queue。让另一个线程在此队列上等待,并在出现新项目时立即打印消息。

            【讨论】:

              【解决方案6】:

              我不确定我是否看到使用的问题: threading.activeCount()

              要跟踪仍处于活动状态的线程数?

              即使您在开始之前不知道要启动多少线程,它似乎也很容易跟踪。我通常通过列表推导生成线程集合,然后使用 activeCount 与列表大小进行简单比较可以告诉你有多少已经完成。

              请看这里:http://docs.python.org/library/threading.html

              或者,一旦你有了你的线程对象,你就可以在线程对象中使用 .isAlive 方法来检查。

              我刚刚通过将它扔到我拥有的多线程程序中进行检查,它看起来不错:

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

              在线程打开和关闭时给我一个 True/False 列表。所以你应该能够做到这一点并检查任何 False 以查看是否有任何线程完成。

              【讨论】:

                【解决方案7】:

                由于我在应用程序中使用的线程的性质,我使用了一种稍微不同的技术。为了说明,这是我编写的一个测试带程序的片段,用于为我的线程类搭建一个屏障类:

                   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()

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2013-12-05
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-12-08
                  • 1970-01-01
                  • 2021-10-29
                  • 1970-01-01
                  相关资源
                  最近更新 更多