You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Tornado autoreload模块配置后失效问题求助

Tornado autoreload 模块内配置后无法正常工作的原因与解决

问题场景

我在自定义的MyTornadoApp类中配置了autoreload功能,初始化时调用tornado.autoreload.start(),但实际运行时只有在主脚本的main()函数中再次调用该方法,autoreload才能触发重载。同时重复调用会出现警告:tornado.autoreload started more than once in the same process。

自定义模块代码(tornadoapp.py)

import os
import tornado.autoreload
import tornado.web

class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello from index handler!")

class MyTornadoApp:
    """Setup my custom tornado app with default settings"""

    # default tornado settings
    default_settings = dict(
        debug=False,
        autoreload=True,
        compress_response=True,
        port=8080,
    )

    default_handlers = [
        (r"/", IndexHandler),
    ]

    def __init__(self, user_settings):
        self.options = {**self.default_settings, **user_settings}

        if self.options['autoreload'] == True:
            self._autoreload_config()

        self.tornado = tornado.web.Application(self.default_handlers,
                                               **self.options)

    def _autoreload_config(self):
        """Setup autoreload for tornado"""
        print("Setting up autoreload for tornado...")
        # autoreload (exclusive) monitor file
        monitoring_file = os.path.abspath('autoreload')
        if not os.path.isfile(monitoring_file):
            with open(monitoring_file, 'w', encoding='UTF-8') as f:
                f.write('Do NOT delete. Monitoring changes in this file!')
        tornado.autoreload.watch(monitoring_file)
        tornado.autoreload.start()

主脚本代码

import asyncio
import tornado.web
from tornadoapp import MyTornadoApp

async def main():
    ################################################################
    #   Why do I need this in order to autoreload work properly???
    ################################################################
    if app.options['autoreload'] == True:
        tornado.autoreload.start()

    app.tornado.listen(app.options['port'])
    print(f"Tornado is listening on port {app.options['port']}")

    await asyncio.Event().wait()

if __name__ == "__main__":
    my_settings = dict(
        debug=False,
        autoreload=True,
    )
    app = MyTornadoApp(my_settings)
    asyncio.run(main())

原因分析

这不是Bug,是Tornado autoreload的运行机制特性,核心原因如下:

  • 事件循环未初始化时调用start()无效:在MyTornadoApp.__init__中调用tornado.autoreload.start()时,asyncio的事件循环还未启动(asyncio.run()在主入口代码中才执行)。Tornado的autoreload依赖活跃的事件循环定时检查文件变化,没有事件循环的情况下,start()无法启动监听任务。
  • 重复调用start()的警告原因:在main()中再次调用start()时,事件循环已初始化,autoreload成功启动,但之前在__init__中的调用是无效的,重复调用就会触发警告——该警告无害,但说明首次调用未起到作用。
  • settings配置的作用:你已经在Application的settings中设置了autoreload=True,Tornado会在服务启动时自动处理autoreload初始化,前提是事件循环已准备好。手动提前调用watch()和start()反而打乱了默认流程。

正确配置方式

不需要手动调用tornado.autoreload.start(),只需遵循以下步骤:

修改后的MyTornadoApp类

import os
import tornado.autoreload
import tornado.web

class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello from index handler!")

class MyTornadoApp:
    """Setup my custom tornado app with default settings"""

    # default tornado settings
    default_settings = dict(
        debug=False,
        autoreload=True,
        compress_response=True,
        port=8080,
    )

    default_handlers = [
        (r"/", IndexHandler),
    ]

    def __init__(self, user_settings):
        self.options = {**self.default_settings, **user_settings}
        self.tornado = tornado.web.Application(self.default_handlers,
                                               **self.options)
        self._monitoring_file = os.path.abspath('autoreload')

    def setup_autoreload(self):
        """Setup custom autoreload watches after event loop is ready"""
        if not self.options['autoreload']:
            return
        print("Setting up autoreload for tornado...")
        if not os.path.isfile(self._monitoring_file):
            with open(self._monitoring_file, 'w', encoding='UTF-8') as f:
                f.write('Do NOT delete. Monitoring changes in this file!')
        tornado.autoreload.watch(self._monitoring_file)
        # 无需手动调用start(),Tornado会自动处理

修改后的主脚本

import asyncio
import tornado.web
from tornadoapp import MyTornadoApp

async def main():
    app.setup_autoreload()
    app.tornado.listen(app.options['port'])
    print(f"Tornado is listening on port {app.options['port']}")

    await asyncio.Event().wait()

if __name__ == "__main__":
    my_settings = dict(
        debug=False,
        autoreload=True,
    )
    app = MyTornadoApp(my_settings)
    asyncio.run(main())

额外说明

  • 如果开启debug=True,Tornado会自动启用autoreload、取消模板缓存等调试特性,此时无需单独设置autoreload=True。
  • 手动调用tornado.autoreload.start()只有在事件循环已经启动的情况下才有效,否则无法创建定时检查任务。

内容的提问来源于stack exchange,提问作者bgeneto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 06:25:22