Почему мой многопроцессный многопроцессорный скрипт Python не завершается должным образом? - PullRequest
4 голосов
/ 04 февраля 2012

У меня есть серверный скрипт, который мне нужно для корректного завершения работы. При тестировании обычных try..except утверждений я понял, что Ctrl-C работает не так, как обычно. Обычно я бы обернул долго выполняющиеся задачи, как это

try:
    ...
except KeyboardInterrupt:
    #close the script cleanly here

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

Первоначальная версия была реализована с использованием Process из multiprocessing. Я переписал скрипт, используя Thread из threading, но та же проблема там. Я использовал threading много раз прежде, но я новичок в библиотеке multiprocessing. В любом случае, я никогда не сталкивался с таким поведением Ctrl-C.

Обычно я всегда использовал часовые и т. Д. Для упорядоченного закрытия экземпляров Queues и Thread, но этот скрипт просто завершается без ответа.

Наконец, я попытался переопределить signal.SIGINT так же, как это

def handler(signal, frame):
    print 'Ctrl+C'

signal.signal(signal.SIGINT, handler)
...

Здесь Ctrl+C фактически было перехвачено, но обработчик не выполняется, он никогда ничего не печатает.

Помимо аспекта threading / multiprocessing, части скрипта содержат C++ SWIG объектов. Я не знаю, имеет ли это какое-либо отношение к этому. Я использую Python 2.7.2 на OS X Lion.

Итак, несколько вопросов:

  1. Что здесь происходит?
  2. Как я могу отладить это?
  3. Что мне нужно выучить, чтобы понять основную причину?

ПОЖАЛУЙСТА, ОБРАТИТЕ ВНИМАНИЕ: внутренняя часть скрипта проприетарна, поэтому я не могу привести примеры кода. Однако я очень хочу получать указатели, чтобы я мог отладить это сам. Я достаточно опытен, чтобы понять, может ли кто-нибудь указать мне правильное направление.

РЕДАКТИРОВАТЬ: Я начал комментировать импорт и т. Д., Чтобы увидеть, что вызвало странное поведение, и я сузил его до импорта C++ SWIG библиотеки. Есть идеи, почему импортировать библиотеку C++ SWIG 'украдет' Ctrl-C? Однако я не автор виновной библиотеки, и мой опыт работы с SWIG ограничен, поэтому я не знаю, с чего начать ...

РЕДАКТИРОВАТЬ 2: Я только что попробовал тот же сценарий на машине с Windows, и в Windows 7 Ctrl-C перехватывается, как ожидалось. Я не собираюсь беспокоиться по поводу части OS X, скрипт все равно будет работать в среде Windows.

Ответы [ 3 ]

4 голосов
/ 04 февраля 2012

Это может быть связано с тем, как Python управляет потоками, сигналами и вызовами C.

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

Фактически, длинные операции могут блокировать все.

Учтите это:

>>> nums = xrange(100000000)
>>> -1 in nums
False (after  ~ 6.6 seconds)
>>>

Теперь попробуйте нажать Ctrl-C (непрерывно!)

>>> nums = xrange(100000000)
>>> -1 in nums
^C^C^C   (nothing happens, long pause)
...
KeyboardInterrupt
>>>

Причина, по которой Ctrl-C не работает с многопоточными программами, заключается в том, что основной поток часто блокируется.бесперебойное объединение или блокировка потоков (например, любое ожидание, соединение или просто пустой пустой основной поток, что в фоновом режиме заставляет python присоединяться к любым порожденным потокам).

Попробуйте вставить простой

while True:
    time.sleep(1)

в ваш основной поток.

Если у вас есть долго работающая функция C, выполняйте обработку сигналов на уровне C (пусть Сила будет с вами!),

Это в значительной степени основано на видео Дэвида Бизли на эту тему.

1 голос
/ 04 февраля 2012

Это происходит потому, что что-то еще может перехватить KeyboardInterupt, а затем вызвать другое исключение или просто вернуть None. Вы все равно должны получить трассировку, чтобы помочь отладке. Вам нужно захватить вывод stderr или запустить ваш скрипт с параметром командной строки -i, чтобы вы могли видеть трассировку. Кроме того, добавьте еще один блок кроме, чтобы перехватить все остальные исключения.

Если вы подозреваете, что вызов функции C ++ перехватывает CTRL + C, попробуйте перехватить его вывод. Если функция C ничего не возвращает, то вы ничего не можете сделать, кроме как попросить автора добавить обработку исключений, коды возврата и т. Д.

try:
    #Doing something proprietary  ...
    #catch the function call output
    result = yourCFuncCall()

    #raise an exception if it's not what you expected
    if result is None:
        raise ValueError('Unexpected Result')

except KeyboardInterupt:
    print('Must be a CTRL+C')
    return

except:
    print('Unhandled Exception')
    raise
0 голосов
/ 04 февраля 2012
...