7

我有一个运行 Twisted 的应用程序,它reactor.run()在启动其他一些线程(包括 CherryPy Web 服务器)后在我的主线程中启动反应器。这是一个程序,当在 Linux 上按下 Ctrl+C 而不是在 Windows 上时,它会干净地关闭:

from threading import Thread
from signal import signal, SIGINT

import cherrypy

from twisted.internet import reactor
from twisted.web.client import getPage

def stop(signum, frame):
    cherrypy.engine.exit()
    reactor.callFromThread(reactor.stop)
signal(SIGINT, stop)

class Root:
    @cherrypy.expose
    def index(self):
        reactor.callFromThread(kickoff)
        return "Hello World!"

cherrypy.server.socket_host = "0.0.0.0"
Thread(target=cherrypy.quickstart, args=[Root()]).start()

def print_page(html):
    print(html)

def kickoff():
    getPage("http://acpstats/account/login").addCallback(print_page)

reactor.run()

我相信 CherryPy 是这里的罪魁祸首,因为这是我在没有 CherryPy 的情况下编写的另一个程序,当按下 Ctrl+C 时,它会在 Linux 和 Windows 上完全关闭:

from time import sleep
from threading import Thread
from signal import signal, SIGINT

from twisted.internet import reactor
from twisted.web.client import getPage

keep_going = True
def stop(signum, frame):
    global keep_going
    keep_going = False
    reactor.callFromThread(reactor.stop)
signal(SIGINT, stop)

def print_page(html):
    print(html)

def kickoff():
    getPage("http://acpstats/account/login").addCallback(print_page)

def periodic_downloader():
    while keep_going:
        reactor.callFromThread(kickoff)
        sleep(5)

Thread(target=periodic_downloader).start()
reactor.run()

有谁知道问题是什么?这是我的难题:

  • 在 Linux 上一切正常
  • 在 Windows 上,我可以reactor.callFromThread在 CherryPy 未运行时从信号处理程序调用函数
  • 当 CherryPy 运行时,我从信号处理程序调用使用reactor.callFromThread的任何函数都不会执行(我已经验证信号处理程序本身确实被调用)

我能做些什么呢?如何在运行 CherryPy 时从信号处理程序关闭 Windows 上的 Twisted?这是一个错误,还是我只是错过了这两个项目中任何一个文档的一些重要部分?

4

1 回答 1

14

当您调用 quickstart 时,CherryPy 默认处理信号。在您的情况下,您可能应该只展开只有几行的快速入门,然后进行选择。这基本上是快速入门在主干中所做的事情:

if config:
    cherrypy.config.update(config)

tree.mount(root, script_name, config)

if hasattr(engine, "signal_handler"):
    engine.signal_handler.subscribe()
if hasattr(engine, "console_control_handler"):
    engine.console_control_handler.subscribe()

engine.start()
engine.block()

在您的情况下,您不需要信号处理程序,因此您可以省略它们。如果你不是从主线程启动 CherryPy,你也不需要调用 engine.block。Engine.block() 只是一种使主线程不立即终止的方法,而是等待进程终止(这样 autoreload 工作可靠;某些平台在从除主线程之外的任何线程调用 execv 时遇到问题)。

如果您删除 block() 调用,您甚至不需要快速启动中的 Thread()。所以,替换你的行:

Thread(target=cherrypy.quickstart, args=[Root()]).start()

和:

cherrypy.tree.mount(Root())
cherrypy.engine.start()
于 2009-07-03T16:14:12.200 回答