【问题标题】:How to exit the entire application from a Python thread?如何从 Python 线程中退出整个应用程序?
【发布时间】:2010-12-02 03:48:40
【问题描述】:

如何从其中一个线程中退出整个 Python 应用程序? sys.exit() 只会终止调用它的线程,所以没有任何帮助。

我不想使用os.kill() 解决方案,因为这不是很干净。

【问题讨论】:

    标签: python multithreading


    【解决方案1】:

    简答:使用os._exit。

    举例说明:

    我从a tutorial on DevShed 中提取并稍微修改了一个简单的线程示例:

    import threading, sys, os
    
    theVar = 1
    
    class MyThread ( threading.Thread ):
    
       def run ( self ):
    
          global theVar
          print 'This is thread ' + str ( theVar ) + ' speaking.'
          print 'Hello and good bye.'
          theVar = theVar + 1
          if theVar == 4:
              #sys.exit(1)
              os._exit(1)
          print '(done)'
    
    for x in xrange ( 7 ):
       MyThread().start()
    

    如果您将sys.exit(1) 注释掉,则脚本将在第三个线程打印出来后终止。如果您使用sys.exit(1) 并注释掉os._exit(1),则第三个线程不打印(done),程序将运行所有七个线程。

    os._exit "通常应该只在 fork() 之后的子进程中使用" -- 并且一个单独的线程足够接近您的目的。另请注意,该手册页中os._exit 之后列出了几个枚举值,您应该更喜欢将它们作为os._exit 的参数,而不是像我在上面的示例中使用的简单数字。

    【讨论】:

    • 这在 docker 容器中运行时特别有效。 docker 容器中的问题是我们无法杀死 pid 1。使用 os._exit(1) 有效。
    【解决方案2】:

    如果除主线程之外的所有线程都是守护进程,最好的方法通常是thread.interrupt_main()——任何线程都可以使用它在主线程中引发KeyboardInterrupt,这通常可以合理地从主线程退出主线程(包括被调用的主线程中的终结器等)。

    当然,如果这导致某些非守护线程保持整个进程处于活动状态,您需要按照 Mark 的建议跟进 os._exit ——但我认为这是最后的手段(有点像 @ 987654324@;-) 因为它非常粗暴地终止事物(终结器未运行,包括 try/finally 块、with 块、atexit 函数等)。

    【讨论】:

      【解决方案3】:

      在某些情况下使用thread.interrupt_main() 可能无济于事。 KeyboardInterrupts 常用于命令行应用程序中,用于退出当前命令或清理输入行。

      此外,os._exit 将立即终止进程,而不会在您的代码中运行任何 finally 块,这可能很危险(例如,文件和连接不会关闭)。

      我找到的解决方案是在引发自定义异常的主线程中注册一个信号处理程序。使用后台线程触发信号。

      import signal
      import os
      import threading
      import time
      
      
      class ExitCommand(Exception):
          pass
      
      
      def signal_handler(signal, frame):
          raise ExitCommand()
      
      
      def thread_job():
          time.sleep(5)
          os.kill(os.getpid(), signal.SIGUSR1)
      
      
      signal.signal(signal.SIGUSR1, signal_handler)
      threading.Thread(target=thread_job).start()  # thread will fire in 5 seconds
      try:
          while True:
              user_input = raw_input('Blocked by raw_input loop ')
              # do something with 'user_input'
      except ExitCommand:
          pass
      finally:
          print('finally will still run')
      

      相关问题:

      【讨论】:

      • 这不适用于 Windows AttributeError: module 'signal' has no attribute 'SIGUSR1'
      • 对于 Windows 是否有替代方案?
      【解决方案4】:

      退出整个程序最简单的方法是,我们应该使用进程ID(pid)终止程序。

      import os
      import psutil
      
      current_system_pid = os.getpid()
      
      ThisSystem = psutil.Process(current_system_pid)
      ThisSystem.terminate()
      

      要安装 psutl:- “pip install psutil”

      【讨论】:

      • 这个答案是我挣扎了几天想要的。
      • 在我看来,这是对这个问题的最简单和最好的答案。谢谢!
      • 其实还有一种更简单的方法,不需要引入任何依赖:os.kill(os.getpid(), signal.SIGTERM)
      猜你喜欢
      • 2011-05-04
      • 2021-11-27
      • 2011-02-09
      • 2012-04-24
      • 2015-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-13
      相关资源
      最近更新 更多