twisted - 通过 KeyboardInterrupt 中断回调

发布于 2024-10-01 04:02:14 字数 822 浏览 8 评论 0原文

我目前正在使用 Twisted 在回调内的 for 循环中重复执行任务,但如果用户通过 Ctrl-C 发出键盘中断,则希望反应器打破回调中的循环(一)。根据我的测试,反应器仅在回调结束时停止或处理中断。

有没有办法在回调运行过程中向回调或错误处理程序发送键盘中断?

干杯,

克里斯

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

I'm currently repeating a task in a for loop inside a callback using Twisted, but would like the reactor to break the loop in the callback (one) if the user issues a KeyboardInterrupt via Ctrl-C. From what I have tested, the reactor only stops or processes interrupts at the end of the callback.

Is there any way of sending a KeyboardInterrupt to the callback or the error handler in the middle of the callback run?

Cheers,

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()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

诗化ㄋ丶相逢 2024-10-08 04:02:14

我得到了这个工作花花公子。触发的 SIGINT 为我的代码中的任何正在运行的任务设置一个标志 running,并另外调用 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()

I got this working dandy. The fired SIGINT sets a flag running for any running task in my code, and additionally calls reactor.callFromThread(reactor.stop) to stop any twisted running code:

#!/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()
沒落の蓅哖 2024-10-08 04:02:14

这是有意避免(半)抢占,因为 Twisted 是一个协作式多任务系统。 Ctrl-C 在 Python 中通过解释器在启动时安装的 SIGINT 处理程序进行处理。处理程序在调用时会设置一个标志。执行每个字节代码后,解释器检查该标志。如果已设置,则此时将引发 KeyboardInterrupt。

反应堆安装了自己的 SIGINT 处理程序。这取代了解释器处理程序的行为。反应堆的处理程序启动反应堆关闭。由于它不会引发异常,因此它不会中断正在运行的任何代码。循环(或其他)完成,当控制返回反应堆时,关闭继续进行。

如果您希望使用 Ctrl-C(即 SIGINT)引发 KeyboardInterrupt,那么您可以使用信号模块恢复 Python 的 SIGINT 处理程序:

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

但是请注意,如果您在 Twisted 的代码运行时发送 SIGINT,而不是您自己的代码,应用程序代码中,行为未定义,因为 Twisted 不希望被 KeyboardInterrupt 中断。

This is intentional to avoid (semi-)preemption, since Twisted is a cooperative multitasking system. Ctrl-C is handled in Python with a SIGINT handler installed by the interpreter at startup. The handler sets a flag when it is invoked. After each byte code is executed, the interpreter checks the flag. If it is set, KeyboardInterrupt is raised at that point.

The reactor installs its own SIGINT handler. This replaces the behavior of the interpreter's handler. The reactor's handler initiates reactor shutdown. Since it doesn't raise an exception, it doesn't interrupt whatever code is running. The loop (or whatever) gets to finish, and when control is returned to the reactor, shutdown proceeds.

If you'd rather have Ctrl-C (ie SIGINT) raise KeyboardInterrupt, then you can just restore Python's SIGINT handler using the signal module:

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

Note, however, that if you send a SIGINT while code from Twisted is running, rather than your own application code, the behavior is undefined, as Twisted does not expect to be interrupted by KeyboardInterrupt.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文