【问题标题】:Python script can't be terminated through Ctrl+C or Ctrl+BreakPython 脚本无法通过 Ctrl+C 或 Ctrl+Break 终止
【发布时间】:2017-04-12 22:20:22
【问题描述】:

我有一个名为myMain.py 的简单python 脚本可以自动执行另一个带有增量编号的python 程序,并且我在CentOS 7 上运行它:

#!/usr/bin/python

import os
import sys
import time

def main():
    step_indicator = ""
    arrow = ">"
    step = 2
    try:
        for i in range(0,360, step):
            step_percentage = float(i)/360.0 * 100
            if i % 10 == 0:
                step_indicator += "="
            os.system("python myParsePDB.py -i BP1.pdb -c 1 -s %s" % step)
            print("step_percentage%s%s%.2f" % (step_indicator,arrow,step_percentage)+"%")
    except KeyboardInterrupt:
        print("Stop me!")
        sys.exit(0)


if __name__ == "__main__":
    main()

目前我只知道这个脚本是单线程安全的,但我不能用Ctrl+C 键盘中断来终止它。

我已经阅读了一些相关问题:例如Cannot kill Python script with Ctrl-CStopping python using ctrl+c 我意识到Ctrl+Z 不会杀死进程,它只会暂停进程并将进程保持在后台。 Ctrl+Break 也适用于我的情况,我认为它只会终止我的主线程但保留子进程。

我还注意到调用os.system() 会从当前执行的进程中产生一个子进程。同时,我还有os 文件I/O 函数和os.system("rm -rf legacy/*") 将在myParsePDB.py 中被调用,这意味着这个myParsePDB.py 子进程也会产生子进程。然后,如果我想在myMain.py 中捕获Ctrl+C,我应该只守护myMain.py 还是应该在每个进程产生时守护它们?

【问题讨论】:

  • 是否有必要在子进程中运行myParsePDB?难道你不能把它写成一个普通的模块,你可以从这个脚本调用而不是使用os.system吗?您应该能够使用 shutil.rmtree 实现 rm 功能
  • @TadhgMcDonald-Jensen 必须运行myParsePDBrm 只是 myParsePDB 的一小部分。

标签: python asynchronous scripting operating-system signal-handling


【解决方案1】:

这是处理信号处理时可能出现的一般问题。 Python 信号也不例外,它是操作系统信号的包装器。因此,python中的信号处理取决于操作系统、硬件和许多条件。但是,如何处理这些问题是类似的。

根据本教程,我将引用以下段落:signal – Receive notification of asynchronous system events

信号是一种操作系统功能,它提供了一种方法 将事件通知您的程序,并处理它 异步。它们可以由系统本身生成,也可以发送 从一个过程到另一个过程。由于信号中断了常规流程 在您的程序中,有可能某些操作(尤其是 I/O) 如果在中间收到信号,可能会产生错误。

信号由整数标识,并在操作中定义 系统 C 头文件。 Python 公开了适用于 平台作为信号模块中的符号。对于下面的例子,我 将使用 SIGINT 和 SIGUSR1。两者通常都是为所有 Unix 定义的 和类 Unix 系统。

在我的代码中:

os.system("python myParsePDB.py -i BP1.pdb -c 1 -s %s" % step) 在 for 循环中会执行一段时间,并且会在 I/O 文件上花费一些时间。如果键盘中断传递太快,写文件后没有异步捕获,信号可能在操作系统中被阻塞,所以我的执行仍然是try 子句for循环。 (执行期间检测到的错误称为异常,并非无条件致命:Python Errors and Exceptions)。

因此,让它们异步的最简单方法是等待:

try:
    for i in range(0,360, step):
        os.system("python myParsePDB.py -i BP1.pdb -c 1 -s %s" % step)
        time.sleep(0.2)
except KeyboardInterrupt:
    print("Stop me!")
    sys.exit(0)

它可能会损害性能,但它保证在等待os.system() 的执行后可以捕获信号。如果需要更好的性能,您可能还想使用其他同步/异步功能来解决问题。

更多unix信号参考,也请看:Linux Signal Manpage

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-30
    • 1970-01-01
    • 1970-01-01
    • 2021-11-23
    相关资源
    最近更新 更多