简体   繁体   English

一段时间后杀死线程的大多数 Pythonic 方法

[英]Most Pythonic way to kill a thread after some period of time

I would like to run a process in a thread (which is iterating over a large database table).我想在一个线程中运行一个进程(它在一个大型数据库表上进行迭代)。 While the thread is running, I just want the program to wait.当线程运行时,我只希望程序等待。 If that thread takes longer then 30 seconds, I want to kill the thread and do something else.如果该线程花费的时间超过 30 秒,我想终止该线程并执行其他操作。 By killing the thread, I mean that I want it to cease activity and release resources gracefully.通过杀死线程,我的意思是我希望它停止活动并优雅地释放资源。

I figured the best way to do this was through a Thread() 's join(delay) and is_alive() functions, and an Event .我认为最好的方法是通过Thread()join(delay)is_alive()函数,以及一个Event Using the join(delay) I can have my program wait 30 seconds for the thread to finish, and by using the is_alive() function I can determine if the thread has finished its work.使用join(delay)我可以让我的程序等待 30 秒让线程完成,并且通过使用is_alive()函数我可以确定线程是否完成了它的工作。 If it hasn't finished its work, the event is set, and the thread knows to stop working at that point.如果它还没有完成它的工作,则设置事件,并且线程知道在该点停止工作。

Is this approach valid, and is this the most pythonic way to go about my problem statement?这种方法是否有效,这是解决我的问题陈述的最 Pythonic 的方法吗?

Here is some sample code:下面是一些示例代码:

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."

Using an Event in this case is works just fine as the signalling mechanism, and is actually recommended in the threading module docs .在这种情况下使用事件作为信号机制工作得很好,实际上在线程模块文档中推荐。

If you want your threads to stop gracefully, make them non-daemonic and use a suitable signalling mechanism such as an Event .如果您希望您的线程正常停止,请将它们设为非守护进程并使用合适的信号机制,例如Event

When verifying thread termination, timeouts almost always introduce room for error.在验证线程终止时,超时几乎总是会给错误带来空间。 Therefore, while using the .join() with a timeout for the initial decision to trigger the event is fine, final verification should be made using a .join() without a timeout.因此,虽然将.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()

This can be simplified to something like this:这可以简化为这样的事情:

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

I'm way late to this game, but I've been wrestling with a similar question and the following appears to both resolve the issue perfectly for me AND lets me do some basic thread state checking and cleanup when the daemonized sub-thread exits:我参加这个游戏已经很晚了,但我一直在努力解决一个类似的问题,以下内容似乎完美地解决了我的问题,并让我在守护子线程退出时进行一些基本的线程状态检查和清理:

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

Yields:产量:

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

I was also struggling to close a thread that was waiting to receive a notification.我也在努力关闭一个等待接收通知的线程。 Tried solution given here by user5737269 but it didn't really work for me.尝试过 user5737269 在这里给出的解决方案,但对我来说并没有真正起作用。 It was getting stuck in second join statement(without timeout one).它陷入了第二个 join 语句(没有超时)。 Struggled a lot but didn't find any solution to this problem.挣扎了很多,但没有找到解决这个问题的任何方法。 Got this solution after thinking sometime: My thread is waiting to receive a message in que.想了想后得到了这个解决方案:我的线程正在等待接收队列中的消息。 I want to close this thread, if no notification is received for 20 seconds.如果 20 秒内没有收到通知,我想关闭此线程。 So, after 20 seconds, I am writing a message to this que so that thread terminates on its own.因此,20 秒后,我正在向此队列写入一条消息,以便线程自行终止。 Here's code:这是代码:

 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!!")

This worked for me.. Hope this idea helps someone!这对我有用..希望这个想法对某人有所帮助!

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

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