Ctrl-C удаляет Python после импорта scipy.stats

Я запускаю 64-битный Python 2.7.3 на Win7 64-бит. Я могу надежно скрыть интерпретатор Python, выполнив следующие действия:

>>> from scipy import stats >>> import time >>> time.sleep(3) 

и нажмите 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 

Это делает невозможным прерывание длительных скудных расчетов.

Googling для «forrtl» и т. П., Я вижу предложения, что такая проблема связана с использованием библиотеки Fortran, которая переопределяет обработку Ctrl-C. Я не вижу ошибки в Scipy trackerbut, учитывая, что Scipy – это библиотека для использования с Python, я считаю это ошибкой. Это нарушает работу Python с Ctrl-C. Есть ли обходной путь для этого?

Изменить. Следуя предложению @ cgohlke, я попытался добавить свой собственный обработчик после импорта scipy. Этот вопрос о связанной проблеме показывает, что добавление обработчика сигнала не работает. Я попытался использовать функцию SetConsoleCtrlHandler для Windows API через pywin32:

 from scipy import stats import win32api def doSaneThing(sig, func=None): print "Here I am" raise KeyboardInterrupt win32api.SetConsoleCtrlHandler(doSaneThing, 1) 

После этого, нажав Ctrl-C, вы можете распечатать «Here I am», но Python по-прежнему падает с ошибкой forrtl. Иногда я также получаю сообщение о том, что функция ConsoleCtrlHandler не удалась, что быстро исчезает.

Если я запустил это в IPython, я могу увидеть обычную трассировку Python KeyboardInterrupt перед ошибкой forrtl. Я также вижу обычную трассировку Python, за которой следует ошибка forrtl, если я вызываю другую ошибку вместо KeyboardInterrupt (например, ValueError):

 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.] 

Кажется, что независимо от того, что делает основной обработчик, он не просто захватывает Ctrl-C напрямую, но реагирует на условие ошибки (ValueError) и сам сбой. Есть ли способ устранить это?

  • Что делать, если я хочу, чтобы 3D сплайн / гладкая интерполяция случайных неструктурированных данных?
  • многомерные доверительные интервалы
  • Фильтрация сигнала с помощью Python lfilter
  • Как использовать функцию streamplot, когда доступны 1D-данные x-координаты, y-координаты, x-скорости и y-скорости?
  • Несколько экземпляров scipy.integrate.ode
  • Scipy разреженные матрицы - назначение и использование различных реализаций
  • Scipy интерполяция, как изменить размер / перемасштабировать матрицу 3x3 до 5x5?
  • Как правильно отображать том с некубильными вокселями в майави
  • 6 Solutions collect form web for “Ctrl-C удаляет Python после импорта scipy.stats”

    Вот вариант вашего размещенного решения, которое может работать. Возможно, есть лучший способ решить эту проблему – или, может быть, даже избежать всего этого, установив переменную среды, которая сообщает DLL пропустить установку обработчика. Надеюсь, это поможет, пока вы не найдете лучший способ.

    И модуль time (строки 868-876), и модуль _multiprocessing (строки 312-321) вызывают SetConsoleCtrlHandler . В случае модуля time его консольный обработчик устанавливает событие Windows, hInterruptEvent . Для основного потока time.sleep ждет этого события через WaitForSingleObject(hInterruptEvent, ul_millis) , где ul_millis – это количество миллисекунд, чтобы спать, если не прервано Ctrl + C. Поскольку обработчик, который вы установили, возвращает True , обработчик time модуля никогда не hInterruptEvent для установки hInterruptEvent , что означает, что sleep не может быть прерван.

    Я попытался использовать imp.init_builtin('time') для imp.init_builtin('time') инициализации модуля time , но, по-видимому, SetConsoleCtrlHandler игнорирует второй вызов. Кажется, обработчик должен быть удален, а затем повторно вставлен. К сожалению, модуль time не экспортирует для этого функцию. Итак, как kludge, просто убедитесь, что вы импортируете модуль time после установки обработчика. Поскольку импорт scipy также импортирует time , вам необходимо предварительно загрузить libifcoremd.dll с помощью ctypes чтобы получить обработчики в правильном порядке. Наконец, добавьте вызов thread.interrupt_main чтобы удостовериться, что обработчик SIGINT Python называется [1] .

    Например:

     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 

    [1] interrupt_main вызывает PyErr_SetInterrupt . Это Py_AddPendingCall Handlers[SIGINT] и вызывает Py_AddPendingCall чтобы добавить checksignals_witharg . В свою очередь это вызывает PyErr_CheckSignals . Поскольку Handlers[SIGINT] сработал, это вызывает Handlers[SIGINT].func . Наконец, если func is signal.default_int_handler , вы получите исключение KeyboardInterrupt .

    Я смог получить половину обхода, сделав это:

     from scipy import stats import win32api def doSaneThing(sig, func=None): return True win32api.SetConsoleCtrlHandler(doSaneThing, 1) 

    Возврат true в обработчике останавливает цепочку обработчиков, так что обработчик обработчика Fortran больше не вызывается. Однако это обходное решение является лишь частичным по двум причинам:

    1. На самом деле это не вызывает KeyboardInterrupt, что означает, что я не могу реагировать на него в коде Python. Это просто возвращает меня к подсказке.
    2. Он не полностью прервет работу так, как обычно делает Ctrl-C в Python. Если в новом сеансе Python я делаю time.sleep(3) и нажимаю Ctrl-C, сон сразу прерывается, и я получаю KeyboardInterrupt. С помощью описанного выше способа спящий режим не прерывается, и управление возвращается в подсказку только после того, как время ожидания увеличивается.

    Тем не менее, это все равно лучше, чем сбой всей сессии. Для меня это ставит вопрос о том, почему SciPy (и любые другие библиотеки Python, которые полагаются на эти библиотеки Intel) не делают этого сами.

    Я оставляю этот ответ неприемлемым в надежде, что кто-то может предоставить реальное решение или обходное решение. Под «реальным» я подразумеваю, что нажатие Ctrl-C во время долгого расчета SciPy должно работать так же, как при загрузке SciPy. (Обратите внимание, что это не значит, что он должен немедленно работать. Вычисления Non-SciPy, такие как простая sum(xrange(100000000)) Python sum(xrange(100000000)) могут не сразу прерываться на Ctrl-C, но, по крайней мере, когда они это делают, они поднимают KeyboardInterrupt.)

    Вот код для исправления DLL, чтобы удалить вызов, который устанавливает обработчик Ctrl-C:

     import os import os.path import imp import hashlib basepath = imp.find_module('numpy')[1] ifcoremd = os.path.join(basepath, 'core', 'libifcoremd.dll') with open(ifcoremd, 'rb') as dll: contents = dll.read() m = hashlib.md5() m.update(contents) patch = {'7cae928b035bbdb90e4bfa725da59188': (0x317FC, '\xeb\x0b'), '0f86dcd44a1c2e217054c50262f727bf': (0x3fdd9, '\xeb\x10')}[m.hexdigest()] if patch: contents = bytearray(contents) contents[patch[0]:patch[0] + len(patch[1])] = patch[1] with open(ifcoremd, 'wb') as dll: dll.write(contents) else: print 'Unknown dll version' 

    EDIT: Вот как я добавил патч для x64. Запустите python.exe в отладчике и установите контрольную SetConsoleCtrlHandler для SetConsoleCtrlHandler пока не получите SetConsoleCtrlHandler к вызову, который вы хотите исправить:

     Microsoft (R) Windows Debugger Version 6.12.0002.633 AMD64 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: .\venv\Scripts\python.exe ... 0:000> .symfix 0:000> bp kernel32!SetConsoleCtrlHandler 0:000> g Breakpoint 0 hit KERNEL32!SetConsoleCtrlHandler: 00007ffc`c25742f0 ff252af00400 jmp qword ptr [KERNEL32!_imp_SetConsoleCtrlHandler (00007ffc`c25c3320)] ds:00007ffc`c25c3320={KERNELBASE!SetConsoleCtrlHandler (00007ffc`bfa12e10)} 0:000> k 5 Child-SP RetAddr Call Site 00000000`007ef7a8 00000000`71415bb4 KERNEL32!SetConsoleCtrlHandler *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\SYSTEM32\python27.dll - 00000000`007ef7b0 00000000`7035779f MSVCR90!signal+0x17c 00000000`007ef800 00000000`70237ea7 python27!PyOS_getsig+0x3f 00000000`007ef830 00000000`703546cc python27!Py_Main+0x21ce7 00000000`007ef880 00000000`7021698c python27!Py_InitializeEx+0x40c 0:000> g Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec 5 2015, 20:40:30) [MSC v.1500 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import numpy ... Breakpoint 0 hit KERNEL32!SetConsoleCtrlHandler: 00007ffc`c25742f0 ff252af00400 jmp qword ptr [KERNEL32!_imp_SetConsoleCtrlHandler (00007ffc`c25c3320)] ds:00007ffc`c25c3320={KERNELBASE!SetConsoleCtrlHandler (00007ffc`bfa12e10)} 0:000> k 5 Child-SP RetAddr Call Site 00000000`007ec308 00000000`7023df6e KERNEL32!SetConsoleCtrlHandler 00000000`007ec310 00000000`70337877 python27!PyTime_DoubleToTimet+0x10ee 00000000`007ec350 00000000`7033766d python27!PyImport_IsScript+0x4f7 00000000`007ec380 00000000`70338bf2 python27!PyImport_IsScript+0x2ed 00000000`007ec3b0 00000000`703385a9 python27!PyImport_ImportModuleLevel+0xc82 0:000> g ... >>> import scipy.stats ... Breakpoint 0 hit KERNEL32!SetConsoleCtrlHandler: 00007ffc`c25742f0 ff252af00400 jmp qword ptr [KERNEL32!_imp_SetConsoleCtrlHandler (00007ffc`c25c3320)] ds:00007ffc`c25c3320={KERNELBASE!SetConsoleCtrlHandler (00007ffc`bfa12e10)} 0:000> k 5 *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Users\kevin\Documents\\venv\lib\site-packages\numpy\core\libifcoremd.dll - Child-SP RetAddr Call Site 00000000`007ed818 00007ffc`828309eb KERNEL32!SetConsoleCtrlHandler 00000000`007ed820 00007ffc`828dfa44 libifcoremd!GETEXCEPTIONPTRSQQ+0xdb 00000000`007ed880 00007ffc`828e59d7 libifcoremd!for_lt_ne+0xc274 00000000`007ed8b0 00007ffc`828e5aff libifcoremd!for_lt_ne+0x12207 00000000`007ed8e0 00007ffc`c292ddc7 libifcoremd!for_lt_ne+0x1232f 0:000> ub 00007ffc`828309eb libifcoremd!GETEXCEPTIONPTRSQQ+0xbb: 00007ffc`828309cb 00e8 add al,ch 00007ffc`828309cd df040b fild word ptr [rbx+rcx] 00007ffc`828309d0 0033 add byte ptr [rbx],dh 00007ffc`828309d2 c9 leave 00007ffc`828309d3 ff15bf390e00 call qword ptr [libifcoremd!for_lt_ne+0x40bc8 (00007ffc`82914398)] 00007ffc`828309d9 488d0d00efffff lea rcx,[libifcoremd!for_rtl_finish_+0x20 (00007ffc`8282f8e0)] 00007ffc`828309e0 ba01000000 mov edx,1 00007ffc`828309e5 ff158d390e00 call qword ptr [libifcoremd!for_lt_ne+0x40ba8 (00007ffc`82914378)] 

    Мы lea инструкцию lea с относительным jmp (который равен 0xeb за которым следует количество байтов для перехода)

     0:000> ? 00007ffc`828309eb - 00007ffc`828309d9 Evaluate expression: 18 = 00000000`00000012 0:000> f 00007ffc`828309d9 L2 eb 10 Filled 0x2 bytes 0:000> ub 00007ffc`828309eb libifcoremd!GETEXCEPTIONPTRSQQ+0xbe: 00007ffc`828309ce 040b add al,0Bh 00007ffc`828309d0 0033 add byte ptr [rbx],dh 00007ffc`828309d2 c9 leave 00007ffc`828309d3 ff15bf390e00 call qword ptr [libifcoremd!for_lt_ne+0x40bc8 (00007ffc`82914398)] 00007ffc`828309d9 eb10 jmp libifcoremd!GETEXCEPTIONPTRSQQ+0xdb (00007ffc`828309eb) 00007ffc`828309db 0d00efffff or eax,0FFFFEF00h 00007ffc`828309e0 ba01000000 mov edx,1 00007ffc`828309e5 ff158d390e00 call qword ptr [libifcoremd!for_lt_ne+0x40ba8 (00007ffc`82914378)] 

    Я не знаю, как файл .dll отображается в этом процессе, поэтому я просто буду искать 0d 00 ef ff ff в файле с шестнадцатеричным редактором. Это уникальный хит, поэтому мы можем рассчитать местоположение в .dll для исправления.

     0:000> db 00007ffc`828309d0 00007ffc`828309d0 00 33 c9 ff 15 bf 39 0e-00 eb 10 0d 00 ef ff ff .3....9......... 00007ffc`828309e0 ba 01 00 00 00 ff 15 8d-39 0e 00 48 8d 0d 0e 9c ........9..H.... 00007ffc`828309f0 09 00 e8 09 2e 0a 00 48-8d 0d 32 9f 09 00 e8 fd .......H..2..... 00007ffc`82830a00 2d 0a 00 48 8d 0d ca ee-0e 00 e8 51 90 00 00 85 -..H.......Q.... 00007ffc`82830a10 c0 0f 85 88 02 00 00 e8-38 fa 0a 00 ff 15 4e 39 ........8.....N9 00007ffc`82830a20 0e 00 89 c1 e8 d7 2d 0a-00 48 8d 05 f8 be 11 00 ......-..H...... 00007ffc`82830a30 45 32 e4 c7 05 0b 4a 13-00 00 00 00 00 41 bd 01 E2....J......A.. 00007ffc`82830a40 00 00 00 48 89 05 06 4a-13 00 ff 15 30 39 0e 00 ...H...J....09.. 0:000> ? 00007ffc`828309d9 - 00007ffc`828309d0 Evaluate expression: 9 = 00000000`00000009 0:000> ? 00007ffc`828309d9 - 00007ffc`828309d0 + 3FDD0 Evaluate expression: 261593 = 00000000`0003fdd9 0:000> 

    Хорошо, я исправил dll на 0x3fdd9 . Давайте посмотрим, как это выглядит сейчас:

     Microsoft (R) Windows Debugger Version 6.12.0002.633 AMD64 Copyright (c) Microsoft Corporation. All rights reserved. CommandLine: .\venv\Scripts\python.exe ... 0:000> bp libifcoremd!GETEXCEPTIONPTRSQQ+c9 Bp expression 'libifcoremd!GETEXCEPTIONPTRSQQ+c9' could not be resolved, adding deferred bp 0:000> g Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec 5 2015, 20:40:30) [MSC v.1500 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import scipy.stats ... Breakpoint 0 hit libifcoremd!GETEXCEPTIONPTRSQQ+0xc9: 00007ffc`845909d9 eb10 jmp libifcoremd!GETEXCEPTIONPTRSQQ+0xdb (00007ffc`845909eb) 0:000> u libifcoremd!GETEXCEPTIONPTRSQQ+0xc9: 00007ffc`845909d9 eb10 jmp libifcoremd!GETEXCEPTIONPTRSQQ+0xdb (00007ffc`845909eb) 00007ffc`845909db 0d00efffff or eax,0FFFFEF00h 00007ffc`845909e0 ba01000000 mov edx,1 00007ffc`845909e5 ff158d390e00 call qword ptr [libifcoremd!for_lt_ne+0x40ba8 (00007ffc`84674378)] 00007ffc`845909eb 488d0d0e9c0900 lea rcx,[libifcoremd!GETHANDLEQQ (00007ffc`8462a600)] 00007ffc`845909f2 e8092e0a00 call libifcoremd!for_lt_ne+0x30 (00007ffc`84633800) 00007ffc`845909f7 488d0d329f0900 lea rcx,[libifcoremd!GETUNITQQ (00007ffc`8462a930)] 00007ffc`845909fe e8fd2d0a00 call libifcoremd!for_lt_ne+0x30 (00007ffc`84633800) 0:000> 

    Итак, теперь были jmp ing, которые выталкивали аргументы в стек и вызов функции. Поэтому его обработчик Ctrl-C не будет установлен.

    Обход SetControlCtrlHandler : patch SetControlCtrlHandler

     import ctypes SetConsoleCtrlHandler_body_new = '\xC2\x08\x00' if ctypes.sizeof(ctypes.c_void_p) == 4 else '\xC3' try: SetConsoleCtrlHandler_body = (lambda kernel32: (lambda pSetConsoleCtrlHandler: kernel32.VirtualProtect(pSetConsoleCtrlHandler, ctypes.c_size_t(1), 0x40, ctypes.byref(ctypes.c_uint32(0))) and (ctypes.c_char * 3).from_address(pSetConsoleCtrlHandler.value) )(ctypes.cast(kernel32.SetConsoleCtrlHandler, ctypes.c_void_p)))(ctypes.windll.kernel32) except: SetConsoleCtrlHandler_body = None if SetConsoleCtrlHandler_body: SetConsoleCtrlHandler_body_old = SetConsoleCtrlHandler_body[0:len(SetConsoleCtrlHandler_body_new)] SetConsoleCtrlHandler_body[0:len(SetConsoleCtrlHandler_body_new)] = SetConsoleCtrlHandler_body_new try: import scipy.stats finally: if SetConsoleCtrlHandler_body: SetConsoleCtrlHandler_body[0:len(SetConsoleCtrlHandler_body_new)] = SetConsoleCtrlHandler_body_old 

    Установка переменной окружения FOR_DISABLE_CONSOLE_CTRL_HANDLER на 1 кажется, FOR_DISABLE_CONSOLE_CTRL_HANDLER проблему .

    EDIT : В то время как Ctrl + C больше не разбивает python, он также не может остановить текущий расчет.

    Пытаться

     import os os.environ['FOR_IGNORE_EXCEPTIONS'] = '1' import scipy.stats 
    Interesting Posts

    Регистрация Facebook в Google App Engine

    Как настроить параметры в Random Forest, используя Scikit Learn?

    Как не пропустить следующий элемент после itertools.takewhile ()

    Установка библиотеки изображений Python (PIL) на Snow Leopard с обновленным Python 2.6.2

    Как мне получить время выполнения программы Python?

    Как определить свободную переменную в python?

    Есть ли простой способ избавиться от ненужных значений, которые появляются, когда вы используете SSH с помощью библиотеки Python в Paramiko и извлекаете вывод из CLI удаленной машины?

    python, не получая полного ответа

    Обрезано среднее с процентом в Python?

    Правильное поведение демона (из PEP 3143) объяснено

    Моя программа python выполняется быстрее, чем моя java-версия одной и той же программы. Что дает?

    как я могу открыть другой терминал linux для вывода различных типов отладочной информации в python?

    Как удалить таблицу в SQLAlchemy?

    AWS Python Lambda с Oracle

    phantomjs не поддерживает флеш-плеер в Windows-машине

    Python - лучший язык программирования в мире.