Python - twisted reactor - 从线程角度看callLater和callFromThread之间的区别

问题描述 投票:1回答:1

我有一个使用twisted reactor的python类。当它获得SIGINT时;它从信号处理函数调用reactor.callLater(0,sys.exit)

我观察到的是callLater(0, sys.exit),我的过程需要一些时间才能退出,大约30秒,如果我用reactor.callFromThread(sys.exit)替换它,那么我看到我的进程立即退出。

我无法理解这种行为背后的原因,为什么callLater需要时间和callFromThread不是。

python twisted
1个回答
1
投票

这是因为信号处理程序会中断主线程上的正常执行流程。从信号处理程序调用的任何代码都必须能够在程序执行中从任意位置处理程序状态。

例如,考虑一下:

class Foo(object):
    def __init__(self):
        self.x = 0
        self.y = 1

    def bar(self):
        x = self.x
        self.x = self.y
        self.y = x

    def sigint(self):
        print(self.x + self.y)

在正常的执行过程中,你永远不会期望sigint打印除1之外的任何东西。但是如果sigint被安装为信号处理程序并且信号在self.x = self.yself.y = x之间传递,那么它将看到self.x等于1并且self.y等于1并打印2

因此,您通常只能依赖标记为“信号安全”或“可重入安全”的API。这些API的实现方式考虑了信号处理程序的调用方式,避免因意外的中间内部状态而跳闸。例如,Foo类的信号安全版本可能如下所示:

class Foo(object):
    def __init__(self):
        self.x = 0
        self.y = 1
        self._bar_lock = threading.Lock()

    def bar(self):
        with self._bar_lock:
            x = self.x
            self.x = self.y
            self.y = x

    def sigint(self):
        with self._bar_lock:
            print(self.x + self.y)

Twisted的callFromThread信号安全,基本上与线程安全相同。可以从基本上任何点的非主线程调用API并且遇到相同的可能不一致的中间内部状态。为了使callFromThread作为从另一个线程向反应器线程发出信号的方式,它必须考虑这些中间内部状态的可能性 - 并且它会这样做。凭借这一点,在信号处理器内部使用也是安全的。

© www.soinside.com 2019 - 2024. All rights reserved.