Domanda

Al momento sto ripetendo un'operazione in un ciclo for all'interno di un callback utilizzando Contorto, ma vorrei il reattore per rompere il ciclo nel callback (uno) se i problemi degli utenti un KeyboardInterrupt tramite Ctrl-C. Da quanto ho provato, il reattore ferma solo o processi interrupt alla fine della richiamata.

C'è un modo di inviare un KeyboardInterrupt alla richiamata o il gestore di errori nel bel mezzo della corsa richiamata?

Saluti,

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()
È stato utile?

Soluzione

Questa è voluto evitare di prelazione (semi), dal momento che ritorto è un sistema multitasking cooperativo. Ctrl-C è gestita in Python con un gestore SIGINT installato dall'interprete all'avvio. Il gestore imposta un flag quando viene richiamato. Dopo l'esecuzione di ogni codice di byte, l'interprete controlla la bandiera. Se è impostato, KeyboardInterrupt è sollevata in quel punto.

Il reattore viene installato il proprio gestore SIGINT. Questo sostituisce il comportamento del gestore dell'interprete. iniziati gestore del reattore reattore arresto. Dal momento che non solleva un'eccezione, non interrompe qualsiasi codice è in esecuzione. Il loop (o altro) ottiene alla fine, e quando il controllo viene restituito al reattore, procede arresto.

Se si preferisce avere Ctrl-C (cioè SIGINT) rilancio KeyboardInterrupt, allora si può solo ripristinare gestore SIGINT di Python utilizzando il modulo di segnalazione:

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

Si noti, tuttavia, che se si invia un SIGINT mentre il codice da ritorto è in esecuzione, piuttosto che il codice dell'applicazione stessa, non è definito il comportamento, come ritorto non si aspetta di essere interrotto da KeyboardInterrupt.

Altri suggerimenti

ho ottenuto questo damerino di lavoro. Il sparato SIGINT imposta un flag in esecuzione per qualsiasi attività in esecuzione nel mio codice, e inoltre le chiamate reactor.callFromThread (reactor.stop) per fermare qualsiasi codice in esecuzione twisted:

#!/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()
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top