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

Python-twisted reactor-从线程角度看callLater和callFromThread之间的差异,python,twisted,Python,Twisted,我有一个python类,它使用twisted reactor。当它得到信号时;它从信号处理函数调用reactor.callLater(0,sys.exit) 我观察到的是callLater(0,sys.exit)我的进程需要一些时间才能退出,大约30秒,如果我用reactor.callFromThread(sys.exit)替换它,那么我会看到我的进程立即退出 我无法理解这种行为背后的原因,为什么callLater需要时间,而callFromThread则不然。这是因为信号处理程序会中断主线程上

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

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


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

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

例如,考虑这一点:

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.y
self.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
来说,它是从另一个线程向反应器线程发送信号的一种方式,它必须考虑这些中间内部状态的可能性,并且它会这样做。因此,在信号处理程序内部使用也是安全的。

@Jeane Paul Calderon-感谢您的回答,您的意思是使用信号处理程序函数中的callLater()可能会导致数据争用,因此我们看到了此类问题?对吗?对。与callFromThread不同,callLater既不是线程安全的,也不是可重入安全的。