витая - прерывание обратного вызова через KeyboardInterrupt - PullRequest
4 голосов
/ 08 ноября 2010

В настоящее время я повторяю задачу в цикле for внутри обратного вызова, используя Twisted, но хотел бы, чтобы реактор прерывал цикл в обратном вызове (один), если пользователь выдает KeyboardInterrupt через Ctrl-C. Из того, что я проверил, реактор останавливается или обрабатывает прерывания только в конце обратного вызова.

Есть ли способ отправить KeyboardInterrupt в функцию обратного вызова или обработчик ошибок в середине выполнения обратного вызова?

Приветствия

Chris

#!/usr/bin/env python

from twisted.internet import reactor, defer


def one(result):
    print "Start one()"
    for i in xrange(10000):
        print i
    print "End one()"
    reactor.stop()


def oneErrorHandler(failure):
    print failure
    print "INTERRUPTING one()"
    reactor.stop()    


if __name__ == '__main__':

    d = defer.Deferred()
    d.addCallback(one)
    d.addErrback(oneErrorHandler)
    reactor.callLater(1, d.callback, 'result')

    print "STARTING REACTOR..."
    try:
        reactor.run()
    except KeyboardInterrupt:
        print "Interrupted by keyboard. Exiting."
        reactor.stop()

Ответы [ 2 ]

8 голосов
/ 10 ноября 2010

У меня есть этот рабочий денди. Запущенный SIGINT устанавливает флаг running для любой запущенной задачи в моем коде и дополнительно вызывает реактор.callFromThread (реактор.stop) , чтобы остановить любой искаженный код:

#!/usr/bin/env python

import sys
import twisted
import re
from twisted.internet import reactor, defer, task
import signal


def one(result, token):
    print "Start one()"
    for i in xrange(1000):
        print i
        if token.running is False:
            raise KeyboardInterrupt()
            #reactor.callFromThread(reactor.stop) # this doesn't work
    print "End one()"

def oneErrorHandler(failure):
    print "INTERRUPTING one(): Unkown Exception"
    import traceback
    print traceback.format_exc()
    reactor.stop()

def oneKeyboardInterruptHandler(failure):
    failure.trap(KeyboardInterrupt)
    print "INTERRUPTING one(): KeyboardInterrupt"
    reactor.stop()

def repeatingTask(token):
    d = defer.Deferred()
    d.addCallback(one, token)
    d.addErrback(oneKeyboardInterruptHandler)
    d.addErrback(oneErrorHandler)
    d.callback('result')

class Token(object):
    def __init__(self):
        self.running = True

def sayBye():
    print "bye bye."


if __name__ == '__main__':

    token = Token()

    def customHandler(signum, stackframe):
        print "Got signal: %s" % signum
        token.running = False                # to stop my code
        reactor.callFromThread(reactor.stop) # to stop twisted code when in the reactor loop
    signal.signal(signal.SIGINT, customHandler)

    t2 = task.LoopingCall(reactor.callLater, 0, repeatingTask, token)
    t2.start(5) 

    reactor.addSystemEventTrigger('during', 'shutdown', sayBye)

    print "STARTING REACTOR..."
    reactor.run()
6 голосов
/ 08 ноября 2010

Это сделано для того, чтобы избежать (полу) прерывания, поскольку Twisted - это кооперативная многозадачная система. Ctrl-C обрабатывается в Python с помощью обработчика SIGINT, установленного интерпретатором при запуске. Обработчик устанавливает флаг, когда он вызывается. После выполнения каждого байтового кода интерпретатор проверяет флаг. Если он установлен, KeyboardInterrupt повышается в этой точке.

Реактор устанавливает собственный обработчик SIGINT. Это заменяет поведение обработчика интерпретатора. Обработчик реактора инициирует остановку реактора. Поскольку он не вызывает исключение, он не прерывает любой выполняемый код. Цикл (или что-то еще) заканчивается, и когда управление возвращается реактору, отключение продолжается.

Если вы предпочитаете, чтобы Ctrl-C (то есть SIGINT) вызывал KeyboardInterrupt, то вы можете просто восстановить обработчик SIGINT в Python, используя сигнальный модуль:

signal.signal(signal.SIGINT, signal.default_int_handler)

Обратите внимание, однако, что если вы отправляете SIGINT во время выполнения кода из Twisted, а не код своего собственного приложения, поведение не определено, поскольку Twisted не ожидает прерывания KeyboardInterrupt.

...