如何干净地无限期休眠?

4

我的代码中启动了几个线程,我需要在脚本结束时无限期地休眠,而不会对性能造成重大影响1

一种可能的方法是循环无限期并短暂休眠:

while True:
    time.sleep(1)

或者长时间休眠。
time.sleep(4000000)

或者
import signal
signal.pause()

但是:

  • 我无法找到最大时间睡眠可以接受的值(sys.maxint太大了)

  • signal.pause()仅在Unix中实现

  • 第一个“睡眠循环”对我来说看起来不太干净(为什么是1秒而不是10秒或0.1秒?)

有没有一种简洁、pythonic的方式无限制地睡眠?


1我不能直接控制线程,否则我会选择使用threading.Thread.join(),因为线程本身不会结束。


1
为什么?你想要一个工作调度器吗? - Chris_Rands
2
“清洁地睡觉”看起来像是一个矛盾修辞法... - BartoszKP
4
在无限循环中长时间睡眠没有问题。每隔N秒,调度程序将唤醒您的线程,绕过下一个睡眠并继续执行。没有任何伤害;非常快速。您的MQTT库可能有一个可以为您完成此操作的方法。Eclipse Paho MQTT Python文档中展示了client.loop_forever()作为示例。 - Harvey
3
threading.enumerate可以获取包括主线程在内的所有正在运行的线程列表,因此您可以等待(使用join)它们。 - Cristian Ciupitu
考虑到像 while True: i+= 1 这样的内容每秒会增加 i 数百万 次,调用 time.sleep(1) 会引入相对较小的开销,而根据您的粒度进行更长时间的休眠甚至会减少开销。 - chepner
显示剩余6条评论
1个回答

5

threading.enumerate会给你一个包含所有正在运行的线程(包括主线程)的列表,所以你可以这样做:

main_thread = threading.main_thread()
while True:
    L = threading.enumerate()
    L.remove(main_thread)  # or avoid it in the for loop
    for t in L:
        t.join()
while True循环是必要的,以防您的库在等待当前线程完成时创建新线程。
假设在运行enumerate时没有创建新线程,则可以检查L是否只有一个元素(主线程),如果是,则退出循环。结合Tadhg McDonald-Jensen建议使用带有哨兵的iter,结果如下:
main_thread = threading.main_thread()
main_threads = [main_thread, ]  # WARN: can't have more than one thread here
for threads in iter(threading.enumerate, main_threads):
    for t in threads:
        if t == main_thread:
            continue
        t.join()
enumerate返回一个无序列表,因此如果您有多个“主”线程,则顺序开始变得重要。一种解决方案是使用集合,即main_threads = {main_thread, }iter(lambda : set(threading.enumerate()), main_threads)
如果您更喜欢请求宽恕而不是请求许可的EAFP方法,并且在脚本末尾启动了所有线程,则也可以这样做:
for thread in threading.enumerate():
    try:
        thread.join()
    except RuntimeError:
        # trying to join the main thread, which would create a deadlock (see https://docs.python.org/3/library/threading.html#threading.Thread.join for details)
        pass

1
你可能想要稍微修改一下代码,用 while L 替换 while True,这样当没有更多的线程时,可以让程序停止。你也可以使用 for L in iter(threading.enumerate, []):,其基本含义是“不断调用 threading.enumerate() 并在结果不为空的情况下继续运行此循环”。 - Tadhg McDonald-Jensen
@TadhgMcDonald-Jensen,根据您的建议,我扩展了我的答案。感谢您的想法。 - Cristian Ciupitu
1
这比检查空列表更有意义,我真的很喜欢你使用它的方式,尽管我需要指出,如果你想要多个“主线程”,我不确定你能保证它们在列表中出现的顺序,所以我不确定它是否直接适用于多个主线程。无论如何,非常好的解决方案。 - Tadhg McDonald-Jensen
这看起来不是很符合Python的风格,但由于没有更好的答案,我会点赞。 - Audrius Meškauskas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接