【问题标题】:Stop KeyboardInterrupt reaching batch file processor停止 KeyboardInterrupt 到达批处理文件处理器
【发布时间】:2017-12-01 19:34:00
【问题描述】:

我正在 Windows 上用 Python 3 编写一些代码,如下所示:

try:
    do something that takes a long time
    (training a neural network in TensorFlow, as it happens)
except KeyboardInterrupt:
    print('^C')
print a summary of results
still useful even if the training was cut short early

如果使用python foo.py 直接从控制台运行,这将完美运行。

但是,如果对 Python 的调用在批处理文件中,它最终会执行上述所有操作,但仍会使用“终止批处理作业”提示向控制台发送垃圾邮件。

有没有办法阻止这种情况发生?通过在 Python 中完全吃掉 ^C,直接跳出批处理文件或其他方式?

【问题讨论】:

  • 你无法通过 Python 控制它。连接到控制台主机 (conhost.exe) 的每个进程都会在会话服务器 (csrss.exe) 创建的新线程上接收控制台控制事件。 CMD 的处理程序设置一个标志。当它在 Python 退出后恢复其调度循环时,它会看到 Ctrl+C 标志已设置并打印“终止批处理作业”消息。

标签: python windows batch-file windows-console


【解决方案1】:

在批处理文件中使用break (More info here) 命令,这将禁用 CTRL+C 暂停文件

编辑:根据this site的break命令

较新版本的 Windows(Windows ME、Windows 2000、Windows XP 和更高版本)仅包含此命令以实现向后兼容性,并且关闭中断无效。

我亲自测试过这个,可以确认,当我找到解决方法时我会编辑

编辑#2:如果您可以有第二个批处理脚本运行start "" /b /wait cmd /c "yourfile.bat",但已知这会导致其他嵌套批处理文件出现故障

禁用 Ctrl+C 的标志由子进程继承,因此 Python 将不再引发 KeyboardInterrupt。另外,如果从控制台读取被 Ctrl+C 中断而没有从 CRT 获得 SIGINT,我们在 Python 中仍然存在错误。 Python 脚本应通过 ctypes 手动启用 Ctrl+C。使用导入 ctypes; kernel32 = ctypes.WinDLL('kernel32', use_last_error=True);成功 = kernel32.SetConsoleCtrlHandler(None, False)

EDIT #3 正如 Eryksyn(在 cmets 中)所指出的,您可以使用 cytpes启用它;

import ctypes; 
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True); success = kernel32.SetConsoleCtrlHandler(None, False)

编辑 #4: 我想我找到了,试试这个(虽然它可能不起作用)你能使用 threading 导入吗?

import time
from threading import Thread

def noInterrupt():
    for i in xrange(4):
        print i
        time.sleep(1)

a = Thread(target=noInterrupt)
a.start()
a.join()
print "done"

【讨论】:

  • CMD 的start 命令使用CREATE_NEW_PROCESS_GROUP 进程创建标志,这会导致CTRL_C_EVENT 默认被忽略,但您仍会看到CTRL_BREAK_EVENT 的终止请求。
  • 子进程继承了禁用 Ctrl+C 的标志,因此 Python 将不再引发 KeyboardInterrupt。另外,如果从控制台读取被 Ctrl+C 而没有从 CRT 获得SIGINT 中断,我们在 Python 中仍然存在错误。 Python 脚本应通过 ctypes 手动启用 Ctrl+C。使用import ctypes;kernel32 = ctypes.WinDLL('kernel32', use_last_error=True);success = kernel32.SetConsoleCtrlHandler(None, False)
  • ctypes 用于在 Python 中启用 Ctrl+C,而不是禁用。这对附加到控制台的任何其他现有进程没有影响。在执行批处理脚本的父 CMD shell 中仍将禁用 Ctrl+C。然而,由 Python 生成的进程将在启用状态下继承 Ctrl+C。
  • 哦!我的错!我会解决的!真的很抱歉
  • 我看不到线程建议的相关性。只有主线程会为 C 运行时 SIGINT 信号获得 KeyboardInterrupt,而这又是控制台的 CTRL_C_EVENT。我们将竭尽全力在 Python 中启用此控制台控制事件,因此 OP 实际上可以获取和处理KeyboardInterrupt,同时让它对批处理脚本保持禁用状态。这种复杂的设置是通过start 在自己的控制台中运行 Python 脚本的替代方法。后者的优点是在批处理脚本中是自包含的,但代价是使用另一个控制台。
猜你喜欢
  • 2015-01-24
  • 2023-04-05
  • 2021-12-19
  • 2020-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多