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

新手上路,请多包涵

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

I figured the best way to do this was through a Thread() ’s join(delay) and is_alive() functions, and an 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."

原文由 Matthew Moisen 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 454
2 个回答

在这种情况下使用事件作为信号机制工作得很好,实际上在 线程模块文档 中推荐。

如果你想让你的线程优雅地停止,让它们成为非守护进程并使用合适的信号机制,比如 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()

原文由 user5737269 发布,翻译遵循 CC BY-SA 3.0 许可协议

我玩这个游戏来晚了,但我一直在努力解决 一个类似的问题,下面的内容似乎既能为我完美地解决这个问题,又能让我在守护进程子线程退出时进行一些基本的线程状态检查和清理:

 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]

原文由 slumtrimpet 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题