【问题标题】:Most Pythonic way to kill a thread after some period of time一段时间后杀死线程的大多数 Pythonic 方法
【发布时间】:2019-12-11 14:59:20
【问题描述】:

我想在一个线程中运行一个进程(它正在遍历一个大型数据库表)。当线程正在运行时,我只想让程序等待。如果该线程花费的时间超过 30 秒,我想终止该线程并执行其他操作。通过杀死线程,我的意思是我希望它停止活动并优雅地释放资源。

我认为最好的方法是通过Thread()join(delay)is_alive() 函数以及Event。使用join(delay) 我可以让我的程序等待30 秒等待线程完成,通过使用is_alive() 函数我可以确定线程是否已经完成它的工作。如果它还没有完成它的工作,则设置事件,并且线程知道此时停止工作。

这种方法是否有效,这是解决我的问题陈述的最 Pythonic 的方法吗?

这里是一些示例代码:

import threading
import time

# The worker loops for about 1 minute adding numbers to a set
# unless the event is set, at which point it breaks the loop and terminates
def worker(e):
    data = set()
    for i in range(60):
        data.add(i)
        if not e.isSet():
            print "foo"
            time.sleep(1)
        else:
            print "bar"
            break

e = threading.Event()
t = threading.Thread(target=worker, args=(e,))
t.start()

# wait 30 seconds for the thread to finish its work
t.join(30)
if t.is_alive():
    print "thread is not done, setting event to kill thread."
    e.set()
else:
    print "thread has already finished."

【问题讨论】:

    标签: python multithreading


    【解决方案1】:

    在这种情况下使用事件作为信号机制工作得很好,并且 其实是在threading module docs推荐的。

    如果您希望线程优雅地停止,请将它们设为非守护进程并使用 合适的信号机制,例如Event

    在验证线程终止时,超时几乎总是为 错误。因此,在使用 .join() 时,初始超时 触发事件的决定很好,最终验证应使用 .join() 没有超时。

    # wait 30 seconds for the thread to finish its work
    t.join(30)
    if t.is_alive():
        print "thread is not done, setting event to kill thread."
        e.set()
        # The thread can still be running at this point. For example, if the 
        # thread's call to isSet() returns right before this call to set(), then
        # the thread will still perform the full 1 second sleep and the rest of 
        # the loop before finally stopping.
    else:
        print "thread has already finished."
    
    # Thread can still be alive at this point. Do another join without a timeout 
    # to verify thread shutdown.
    t.join()
    

    这可以简化为:

    # Wait for at most 30 seconds for the thread to complete.
    t.join(30)
    
    # Always signal the event. Whether the thread has already finished or not, 
    # the result will be the same.
    e.set()
    
    # Now join without a timeout knowing that the thread is either already 
    # finished or will finish "soon."
    t.join()
    

    【讨论】:

    • 这里的e是什么?以及它如何与 t 相关联?为了完整起见,您能否更新代码?
    • 对于那些仍然对此感到困惑的人:e = threading.Event()(见问题)
    【解决方案2】:

    我玩这个游戏已经很晚了,但我一直在与a similar question 搏斗,以下似乎完美地解决了我的问题,并让我在守护进程时进行一些基本的线程状态检查和清理子-线程退出:

    import threading
    import time
    import atexit
    
    def do_work():
    
      i = 0
      @atexit.register
      def goodbye():
        print ("'CLEANLY' kill sub-thread with value: %s [THREAD: %s]" %
               (i, threading.currentThread().ident))
    
      while True:
        print i
        i += 1
        time.sleep(1)
    
    t = threading.Thread(target=do_work)
    t.daemon = True
    t.start()
    
    def after_timeout():
      print "KILL MAIN THREAD: %s" % threading.currentThread().ident
      raise SystemExit
    
    threading.Timer(2, after_timeout).start()
    

    产量:

    0
    1
    KILL MAIN THREAD: 140013208254208
    'CLEANLY' kill sub-thread with value: 2 [THREAD: 140013674317568]
    

    【讨论】:

    • 如果线程调用一些永远不会返回的外部代码似乎很好。这样可以杀死无响应的线程。
    【解决方案3】:

    我还在努力关闭等待接收通知的线程。 尝试了 user5737269 在这里给出的解决方案,但它并没有真正为我工作。它卡在第二个连接语句中(没有超时)。挣扎了很多,但没有找到任何解决这个问题的方法。经过一段时间思考后得到了这个解决方案: 我的线程正在等待接收 que 中的消息。如果 20 秒内没有收到通知,我想关闭此线程。因此,20 秒后,我正在向该队列写入一条消息,以便线程自行终止。 代码如下:

     q = Queue.Queue()
     t.join(20)
        if t.is_alive():
            print("STOPPING THIS THREAD ....")
            q.put("NO NOTIFICATION RECEIVED")
            t.join(20)
        else:
            print("Thread completed successfully!!")
    

    这对我有用..希望这个想法对某人有所帮助!

    【讨论】:

      猜你喜欢
      • 2017-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-29
      • 2012-10-18
      • 2016-07-10
      • 2018-10-18
      相关资源
      最近更新 更多