我有一个Twisted / PyQt应用程序(除此之外)连接到一堆远程资源。当用户关闭窗口时,我希望尽可能干净地关闭所有连接,如果没有,则强行关闭。
问题是,当我关闭连接时,似乎反应堆不再存在让我这样做。
这是我的应用代码:
# Create app and connect the Twisted/Qt reactors
app = QApplication(sys.argv)
qtreactor.qt4reactor.install()
# Shutdown Twisted when window is closed
@defer.inlineCallbacks
def stop():
print "="*40, "Closing connections..."
yield closeConnections()
print "="*40, "closed."
print "="*40, "Stopping reactor..."
reactor.stop()
print "="*40, "stopped."
app.connect(app, SIGNAL("lastWindowClosed()"), stop)
reactor.runReturn()
rc = app.exec_()
exit(rc)
这是我的清理代码的简化版本:
@defer.inlineCallbacks
def closeConnections():
for connection in connections:
print "Closing connection #%s" % connection
yield threads.deferToThread(popen("/foo/bar/cleanup %s" % connection))
print "Connection closed."
到达第一个print语句,并且执行命令,但是我从来没有得到第二个,也没有多次执行for循环。
我的分析是否正确?问题是反应堆已经关闭,所以我从来没有收到过来自threads.deferToThread的回复?还是有其他问题吗?此外,我该如何解决?
谢谢, 乔纳森
答案 0 :(得分:2)
我不知道 lastWindowClosed() 信号何时触发。然而,即使它在反应堆关闭之前足够早地发射(阻止你做你想做的事情),我确信PyQt不知道如何处理你的{{返回的延迟1}}功能。这意味着在异步清理代码尝试运行时,关闭过程将继续快速进行。可能会在网络关闭到达任何地方之前完成GUI关闭。
所以,请改用stop
。我不知道这是否会比 lastWindowClosed() 稍早或略晚,但它会运行得足够早,反应堆仍然可用,而且< strong>会注意延迟你的函数返回。事实上,关闭将暂停,直到Deferred发生火灾。这为您提供了清理所需的所有时间。
除此之外,你不应该reactor.addSystemEventTrigger('before', 'shutdown', stop)
:
threads.deferToThread(popen("/foo/bar/cleanup %s" % connection))
,而不是调用callable的结果。如上所述,您的代码在reactor线程中运行popen并将文件对象传递给要调用的线程(当然这没有任何意义)deferToThread
将允许您运行子进程而不会阻塞,没有线程,并且不必担心混合线程和进程。如果您不需要reactor.spawnProcess
的所有功能(您似乎没有这样做),另请参阅twisted.internet.utils.getProcessOutput
。