4

現在、Twisted を使用してコールバック内の for ループでタスクを繰り返していますが、ユーザーが Ctrl-C を介して KeyboardInterrupt を発行した場合、リアクターがコールバック (1 つ) でループを中断するようにしたいと考えています。私がテストしたところ、リアクターはコールバックの最後でのみ停止または割り込みを処理します。

コールバックの実行中に、KeyboardInterrupt をコールバックまたはエラー ハンドラに送信する方法はありますか?

乾杯、

クリス

#!/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()
4

2 に答える 2

8

私はこの働くダンディを手に入れました。起動された SIGINT は、コード内の実行中のタスクに対して実行中のフラグを設定し、さらに、reactor.callFromThread(reactor.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()
于 2010-11-10T08:51:33.913 に答える
6

Twisted は協調的なマルチタスク システムであるため、これは (半) プリエンプションを回避するために意図的に行われます。Ctrl-C は、起動時にインタープリターによってインストールされた SIGINT ハンドラーを使用して Python で処理されます。ハンドラーは、呼び出されるとフラグを設定します。各バイトコードが実行された後、インタープリターはフラグをチェックします。設定されている場合、その時点で KeyboardInterrupt が発生します。

リアクターは独自の SIGINT ハンドラーをインストールします。これは、インタープリターのハンドラーの動作を置き換えます。原子炉のハンドラーが原子炉のシャットダウンを開始します。例外が発生しないため、実行中のコードが中断されることはありません。ループ (または何でも) が終了し、制御が原子炉に戻されると、シャットダウンが進行します。

Ctrl-C (つまり SIGINT) で KeyboardInterrupt を発生させたい場合は、シグナル モジュールを使用して Python の SIGINT ハンドラを復元できます。

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

ただし、独自のアプリケーション コードではなく、Twisted からのコードの実行中に SIGINT を送信した場合、Twisted は KeyboardInterrupt によって中断されることを想定していないため、動作は未定義であることに注意してください。

于 2010-11-08T17:40:51.043 に答える