You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何安全终止nohup运行的Python脚本以执行finally块

问题

我用nohup启动了一个Python脚本,脚本包含finally块,发生异常或触发KeyboardInterrupt时,会把队列中剩余条目打印到日志文件。在启动脚本的原Shell中操作一切正常:通过nohup后台启动脚本,用jobs查看进程,fg调回前台后按Ctrl+C,脚本会将队列待处理条目写入日志。但退出该Shell后,无法将进程调回前台发送KeyboardInterrupt;使用kill命令终止进程时,finally块不会执行,导致队列待处理条目丢失。请问有没有办法终止该nohup进程或发送类似KeyboardInterrupt的信号,同时让finally块执行代码?

更新:核心Python代码

try:
    cc = crawler.MultiThreadedWebCrawler(max_workers)
    cc.run_web_crawler()
finally:
    cc.info(script_start_time)
    
# 另一个脚本中info方法的定义:
def info(self, script_start_time):
    print('\n', self.crawl_queue.qsize(), ' 条URL在crawl_queue中:\n')
    while self.crawl_queue.qsize() > 0:
        print(self.crawl_queue.qsize(), ' ', self.crawl_queue.get(), '\n')
    print("脚本启动时间: ", script_start_time)
    print("脚本结束时间: ", datetime.now().strftime('%Y-%m-%d__%H_%M_%S'))

解决方案

  • 发送SIGINT信号模拟Ctrl+C:先通过ps aux | grep 你的脚本文件名找到进程PID,然后执行kill -SIGINT <进程PID>。Python会把这个信号转换成KeyboardInterrupt异常,和前台按Ctrl+C效果一致,能触发finally块执行。
  • 给脚本添加信号监听逻辑:如果默认kill发的SIGTERM信号无法触发finally,可以在脚本开头添加信号处理代码,把SIGTERM转换成KeyboardInterrupt:
    import signal
    
    def handle_signal(signum, frame):
        raise KeyboardInterrupt
    
    # 监听SIGTERM和SIGINT信号
    signal.signal(signal.SIGTERM, handle_signal)
    signal.signal(signal.SIGINT, handle_signal)
    
    之后直接用kill <进程PID>就能触发finally块执行。
  • 处理多线程场景的信号传递:因为你的脚本是多线程爬虫,要确保主线程能接收到信号。如果run_web_crawler用threading启动线程,主线程不要被完全阻塞,同时线程最好设置为非守护线程(daemon=False),或者在finally块里主动终止线程并清理队列,避免线程还在运行时主线程退出。
  • 禁止使用kill -9:kill -9会强制杀死进程,Python没有任何机会执行清理代码,包括finally块,绝对不能用这个命令。

内容的提问来源于stack exchange,提问作者learner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 07:54:25