【问题标题】:Best way to implement a non-blocking wait?实现非阻塞等待的最佳方式?
【发布时间】:2010-07-12 07:41:22
【问题描述】:

在 python 中,如果我想保持一个进程或线程永远运行,我通常可以用一个空的 while 循环来做到这一点:

while 1:
    pass

然而,这会消耗不公平的 CPU 进程。添加一个简短的sleep 会起作用:

import time
while 1:
    time.sleep(0.01)

有没有最好或更清洁的方法?

【问题讨论】:

  • 线程在等待什么?你为什么不做 time.sleep(1000000)?
  • 这是一个类似服务器的应用程序,所以我希望它等待超过几天(1000000 秒)!理论上,一个必须运行永远的线程必须保持运行比非常多的秒数更长的时间
  • 除了睡眠或忙循环之外,线程是否在做任何有用的?如果没有,你能把它去掉吗?如果它正在做一些有价值的事情,那就承认吧!这就是我们需要知道的一点来帮助您。
  • 除了保持进程运行以便其子进程可以继续工作之外,它没有做任何事情
  • 我怀疑这是必要的,因为子进程可以从它们的父进程中分离出来。但是,while True: time.sleep(0x7FFFFFFF) 应该可以工作。

标签: python multithreading


【解决方案1】:

考虑到相当奇怪的要求(一个无需使用太多 CPU 就可以一直运行的进程),这是相当紧凑的:

import threading
dummy_event = threading.Event()
dummy_event.wait() 

...但是,我担心我会屈服于解决您的 Y 而不是您的 X 的诱惑。

此外,如果您的平台不提供threading 模块,这将不起作用。如果您尝试替换 dummy_threading 模块,dummy_event.wait() 会立即返回。

更新:如果您只是为了子进程而保持父进程运行,您可以使用Popen objects 上的wait() 方法,或@987654324 上的join() 方法@对象。这两种方法都会无限期地阻塞,直到子进程结束。如果您正在使用其他一些子流程 API,那么肯定会有等效的功能可用。如果没有,获取进程的PID并使用os.waitpid()。

【讨论】:

    【解决方案2】:

    不要使用忙等待。根据您在等待什么,使用操作系统的阻塞等待功能之一,例如select 在 Unix 上和 WaitForSingleObject/WaitForMultipleObjects 在 Windows 上。

    【讨论】:

    • 感谢您的回答。不过,我不是在等什么。正如问题所暗示的那样,该进程的目标是永远运行直到它被杀死。
    【解决方案3】:

    如果您依赖此脚本执行定期维护,请使用 cron (UNIX) 或计划任务 (Windows)。

    如果您希望等待子流程完成,请使用os.waitpid。

    如果您希望等待文件系统活动,请使用pyinotify。

    【讨论】:

      【解决方案4】:

      睡很短的时间有什么问题?对于现代计算机而言,1 毫秒接近永恒。如果您没有数千个这样的线程(听起来您没有),那么在循环中的每次迭代中休眠一、十、一万或一千万毫秒并没有什么问题。 CPU 甚至不会注意到这个小信号。

      【讨论】:

      • 使用 while 循环等待的坏习惯。你的回答类似于“一个小汽车轮胎在短时间内燃烧有什么问题?”。如果没有其他选择。但这有。很多。问题是要以更清洁的方式做事。
      【解决方案5】:

      可能有人会提出这个老问题,所以我将把它留在这里。 最佳方式是 BlockingScheduler 来自 apscheduler 模块,您还可以使用它定期安排作业(或类似 cron 或其他)

      from datetime import datetime
      import os
      
      from apscheduler.schedulers.blocking import BlockingScheduler
      
      
      def tick():
          print('Tick! The time is: %s' % datetime.now())
      
      
      if __name__ == '__main__':
          scheduler = BlockingScheduler()
          scheduler.add_job(tick, 'interval', seconds=3)
          print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))
      
          try:
              scheduler.start()
          except (KeyboardInterrupt, SystemExit):
              pass
      

      【讨论】:

      • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
      • 我会尽快编辑评论,谢谢
      猜你喜欢
      • 2011-01-07
      • 2012-11-19
      • 2012-10-02
      • 2021-05-26
      • 1970-01-01
      • 2017-11-12
      • 2023-04-07
      • 2015-01-15
      • 1970-01-01
      相关资源
      最近更新 更多