python - Python - 扭曲的反应器 - 从线程的角度来看 callLater 和 callFromThread 之间的区别
问题描述
我有一个使用twisted reactor
. 当它得到 SIGINT 时;它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)
TwistedcallFromThread
是信号安全的,原因与它是线程安全的基本相同。API 可以在基本上任何时候从非主线程调用,并遇到相同的潜在不一致的中间内部状态。为了callFromThread
作为从另一个线程向反应器线程发出信号的一种方式,它必须考虑这些中间内部状态的可能性——它确实这样做了。因此,在信号处理程序中使用也是安全的。
推荐阅读
- botframework - 在将用户话语转发到 LUIS 之前在机器人中预处理用户话语
- information-retrieval - 是否有可以最大化排名结果的平均倒数排名 (MRR) 的学习排名算法?
- javascript - 与 .map() 反应时一次只显示一个元素
- docker - Docker 容器:即使我在构建期间设置了 PATH,也找不到 pip
- python - abs 函数如何使用此代码:abs(3 + 4j)?
- cmake - find_package(ACL REQUIRED) 不会停止处理
- webpack - Webpack 打包和优化
- django - Django 模型覆盖保存方法
- java - 安卓工作室 setContentView(R.layout.activity_login); 即使我的第二个活动名称 activity_login 在布局文件夹中存在,也无法正常工作
- java - 改变 windowTitleBackgroundStyle