如何停止Tornado网络服务器?
我最近在玩一个叫做Tornado web server的东西,到了想要停止这个网络服务器的时候,比如在做单元测试时。Tornado官网上有一个简单的例子可以参考:
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
application = tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
当你调用tornado.ioloop.IOLoop.instance().start()
时,它会让程序(或者当前的线程)停下来。查看源代码中的IOLoop
对象,文档里有关于stop
函数的例子:
To use asynchronous methods from otherwise-synchronous code (such as
unit tests), you can start and stop the event loop like this:
ioloop = IOLoop()
async_method(ioloop=ioloop, callback=ioloop.stop)
ioloop.start()
ioloop.start() will return after async_method has run its callback,
whether that callback was invoked before or after ioloop.start.
不过,我不知道怎么把这个整合进我的程序里。我其实有一个类来封装这个网络服务器(它有自己的start
和stop
函数),但一旦我调用start,程序(或者测试)就会被阻塞。
我尝试过在另一个进程中启动网络服务器(使用multiprocessing
包)。这是封装网络服务器的类:
class Server:
def __init__(self, port=8888):
self.application = tornado.web.Application([ (r"/", Handler) ])
def server_thread(application, port):
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(port)
tornado.ioloop.IOLoop.instance().start()
self.process = Process(target=server_thread,
args=(self.application, port,))
def start(self):
self.process.start()
def stop(self):
ioloop = tornado.ioloop.IOLoop.instance()
ioloop.add_callback(ioloop.stop)
但是,stop似乎并没有完全停止网络服务器,因为在下一个测试中它仍然在运行,即使是这样的测试设置:
def setup_method(self, _function):
self.server = Server()
self.server.start()
time.sleep(0.5) # Wait for web server to start
def teardown_method(self, _function):
self.kstore.stop()
time.sleep(0.5)
我该如何在Python程序中启动和停止Tornado网络服务器呢?
9 个回答
如果你不想麻烦线程的问题,可以捕捉一个键盘中断信号:
try:
tornado.ioloop.IOLoop.instance().start()
# signal : CTRL + BREAK on windows or CTRL + C on linux
except KeyboardInterrupt:
tornado.ioloop.IOLoop.instance().stop()
这里有一个方法,可以从另一个线程停止Tornado。Schildmeijer给了一个很好的提示,但我花了一些时间才弄明白最终的有效示例。
请看下面的内容:
import threading
import tornado.ioloop
import tornado.web
import time
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world!\n")
def start_tornado(*args, **kwargs):
application = tornado.web.Application([
(r"/", MainHandler),
])
application.listen(8888)
print "Starting Torando"
tornado.ioloop.IOLoop.instance().start()
print "Tornado finished"
def stop_tornado():
ioloop = tornado.ioloop.IOLoop.instance()
ioloop.add_callback(ioloop.stop)
print "Asked Tornado to exit"
def main():
t = threading.Thread(target=start_tornado)
t.start()
time.sleep(5)
stop_tornado()
t.join()
if __name__ == "__main__":
main()
我刚遇到这个问题,自己也找到了这个问题的解决方法。根据这个讨论串的信息,我得出了以下结论。我简单地把我之前能正常运行的独立Tornado代码(从所有示例中复制的)中的启动代码放到了一个函数里。然后我把这个函数作为一个线程来调用。在我的情况下,线程的调用是从我现有的代码中进行的,我只是导入了startTornado和stopTornado这两个功能。
上面的建议看起来效果很好,所以我想提供缺失的示例代码。我在Linux的FC16系统上测试了这段代码(并修正了我最开始的一个打字错误)。
import tornado.ioloop, tornado.web
class Handler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
application = tornado.web.Application([ (r"/", Handler) ])
def startTornado():
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
def stopTornado():
tornado.ioloop.IOLoop.instance().stop()
if __name__ == "__main__":
import time, threading
threading.Thread(target=startTornado).start()
print "Your web server will self destruct in 2 minutes"
time.sleep(120)
stopTornado()
希望这能帮助到下一个人。