Bre*_*arn 32 python scipy keyboardinterrupt
我在Win7 64位上运行64位Python 2.7.3.我可以通过这样做可靠地崩溃Python解释器:
>>> from scipy import stats
>>> import time
>>> time.sleep(3)
Run Code Online (Sandbox Code Playgroud)
并在睡眠期间按下Control-C.未引发KeyboardInterrupt; 翻译崩溃了.打印如下:
forrtl: error (200): program aborting due to control-C event
Image PC Routine Line Source
libifcoremd.dll 00000000045031F8 Unknown Unknown Unknown
libifcoremd.dll 00000000044FC789 Unknown Unknown Unknown
libifcoremd.dll 00000000044E8583 Unknown Unknown Unknown
libifcoremd.dll 000000000445725D Unknown Unknown Unknown
libifcoremd.dll 00000000044672A6 Unknown Unknown Unknown
kernel32.dll 0000000077B74AF3 Unknown Unknown Unknown
kernel32.dll 0000000077B3F56D Unknown Unknown Unknown
ntdll.dll 0000000077C73281 Unknown Unknown Unknown
Run Code Online (Sandbox Code Playgroud)
这使得无法中断长时间运行的scipy计算.
谷歌搜索"forrtl"等,我看到这种问题的建议是由于使用了一个覆盖Ctrl-C处理的Fortran库.我没有看到Scipy跟踪器上的错误但是假设Scipy是一个用于Python的库,我会认为这是一个错误.它打破了Python对Ctrl-C的处理.这有什么解决方法吗?
编辑:关注@ cgohlke的建议我尝试在导入scipy后添加自己的处理程序. 关于相关问题的这个问题表明添加信号处理程序不起作用.我尝试通过pywin32 使用Windows API SetConsoleCtrlHandler函数:
from scipy import stats
import win32api
def doSaneThing(sig, func=None):
print "Here I am"
raise KeyboardInterrupt
win32api.SetConsoleCtrlHandler(doSaneThing, 1)
Run Code Online (Sandbox Code Playgroud)
在此之后,按Ctrl-C打印"我在这里",但Python仍然崩溃与forrtl错误.有时我也会收到一条消息,说"ConsoleCtrlHandler功能失败",很快就消失了.
如果我在IPython中运行它,我可以在forrtl错误之前看到正常的Python KeyboardInterrupt回溯.如果我引发一些其他错误而不是KeyboardInterrupt(例如,ValueError),我还会看到正常的Python回溯,然后是forrtl错误:
ValueError Traceback (most recent call last)
<ipython-input-1-08defde66fcb> in doSaneThing(sig, func)
3 def doSaneThing(sig, func=None):
4 print "Here I am"
----> 5 raise ValueError
6 win32api.SetConsoleCtrlHandler(doSaneThing, 1)
ValueError:
forrtl: error (200): program aborting due to control-C event
[etc.]
Run Code Online (Sandbox Code Playgroud)
似乎无论底层处理程序在做什么,它不仅仅是直接捕获Ctrl-C,而是对错误条件(ValueError)做出反应并使自身崩溃.有没有办法消除这个?
Ery*_*Sun 21
以下是您发布的解决方案可能有效的变体.也许有更好的方法来解决这个问题 - 或者甚至可以通过设置一个告诉DLL跳过安装处理程序的环境变量来避免这一切.希望这会有所帮助,直到找到更好的方法.
两个time模块(线868-876)和_multiprocessing模块(线312-321)呼叫SetConsoleCtrlHandler.对于time模块,其控制台控制处理程序设置Windows事件hInterruptEvent.对于主线程,time.sleep等待此事件通过WaitForSingleObject(hInterruptEvent, ul_millis),ul_millis除非被Ctrl + C中断,否则睡眠的毫秒数.由于您安装的处理程序返回True,因此time模块的处理程序永远不会被调用来设置hInterruptEvent,这意味着sleep无法中断.
我尝试使用imp.init_builtin('time')重新初始化time模块,但显然SetConsoleCtrlHandler忽略了第二个调用.似乎必须删除处理程序然后重新插入.不幸的是,该time模块不会为此导出函数.因此,作为kludge,只需确保在安装处理程序后导入time模块.由于还导入了导入,因此您需要预先加载libifcoremd.dll 以按正确的顺序获取处理程序.最后,添加一个调用以确保Python的处理程序被调用[1].scipytimectypesthread.interrupt_mainSIGINT
例如:
import os
import imp
import ctypes
import thread
import win32api
# Load the DLL manually to ensure its handler gets
# set before our handler.
basepath = imp.find_module('numpy')[1]
ctypes.CDLL(os.path.join(basepath, 'core', 'libmmd.dll'))
ctypes.CDLL(os.path.join(basepath, 'core', 'libifcoremd.dll'))
# Now set our handler for CTRL_C_EVENT. Other control event
# types will chain to the next handler.
def handler(dwCtrlType, hook_sigint=thread.interrupt_main):
if dwCtrlType == 0: # CTRL_C_EVENT
hook_sigint()
return 1 # don't chain to the next handler
return 0 # chain to the next handler
win32api.SetConsoleCtrlHandler(handler, 1)
>>> import time
>>> from scipy import stats
>>> time.sleep(10)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyboardInterrupt
Run Code Online (Sandbox Code Playgroud)
[1] interrupt_main电话PyErr_SetInterrupt.这次旅行Handlers[SIGINT]并要求Py_AddPendingCall加入checksignals_witharg.反过来这个叫PyErr_CheckSignals.因为Handlers[SIGINT]被绊倒了,这就叫了Handlers[SIGINT].func.最后,如果func是signal.default_int_handler,你会得到一个KeyboardInterrupt例外.
设置环境变量FOR_DISABLE_CONSOLE_CTRL_HANDLER来1 似乎解决这个问题。
编辑:虽然Ctrl+ C不会再使python崩溃,但它也无法停止当前计算。
| 归档时间: |
|
| 查看次数: |
6343 次 |
| 最近记录: |