Twisted + qtreactor:最后一个窗口关闭后如何清理?

时间:2011-03-28 16:06:24

标签: python pyqt twisted

我有一个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的回复?还是有其他问题吗?此外,我该如何解决?

谢谢, 乔纳森

1 个答案:

答案 0 :(得分:2)

我不知道 lastWindowClosed() 信号何时触发。然而,即使它在反应堆关闭之前足够早地发射(阻止你做你想做的事情),我确信PyQt不知道如何处理你的{{返回的延迟1}}功能。这意味着在异步清理代码尝试运行时,关闭过程将继续快速进行。可能会在网络关闭到达任何地方之前完成GUI关闭。

所以,请改用stop。我不知道这是否会比 lastWindowClosed() 稍早或略晚,但它会运行得足够早,反应堆仍然可用,而且< strong>会注意延迟你的函数返回。事实上,关闭将暂停,直到Deferred发生火灾。这为您提供了清理所需的所有时间。

除此之外,你不应该reactor.addSystemEventTrigger('before', 'shutdown', stop)

  • 您需要将callable传递给threads.deferToThread(popen("/foo/bar/cleanup %s" % connection)),而不是调用callable的结果。如上所述,您的代码在reactor线程中运行popen并将文件对象传递给要调用的线程(当然这没有任何意义)
  • 混合线程和子进程是不确定的。你大部分时间都可以逃脱,我不知道。
  • deferToThread将允许您运行子进程而不会阻塞,没有线程,并且不必担心混合线程和进程。如果您不需要reactor.spawnProcess的所有功能(您似乎没有这样做),另请参阅twisted.internet.utils.getProcessOutput