我目前正在玩烧瓶,我无法弄清楚调试机制的工作原理。为了更确切地说,当我使用应用程序保存Python文件时,我不需要重新启动服务器,当我提出请求时,它将自动加载它。因此,我的问题是,运行程序如何知道它已被更改并响应这种变化?

有帮助吗?

解决方案

烧瓶正在使用werkzug的底层 run_with_reloader 功能(在 serving.py)...本身就是在使用 restart_with_reloaderreloader_loop 在同一文件中创建的函数。

run_with_reloader 产生另一个python过程(再次运行Werkzug,所有与您传递给第一个相同的参数),此新过程使用 thread 模块要生成运行服务器函数的新线程或子过程。然后运行 reloader_loop 等待。

reloader_loop 只需循环浏览已导入的所有模块,并获得了最后的修改日期。然后在指定的间隔(默认为1 s),再次检查所有文件以查看是否已修改。如果有,当前正在运行(奴隶)Werkzug进程退出(终止),其退出代码为3。它退出后,其启动的线程或子过程(实际上正在做工作)也将终止。这 掌握 流程检查以查看出口代码是否为3。如果是,它会产生新的 奴隶 子过程,就像以前一样。否则,它将使用相同的退出代码退出。

这是参考的代码:

def reloader_loop(extra_files=None, interval=1):
    """When this function is run from the main thread, it will force other
    threads to exit when any modules currently loaded change.

    Copyright notice.  This function is based on the autoreload.py from
    the CherryPy trac which originated from WSGIKit which is now dead.

    :param extra_files: a list of additional files it should watch.
    """
    def iter_module_files():
        for module in sys.modules.values():
            filename = getattr(module, '__file__', None)
            if filename:
                old = None
                while not os.path.isfile(filename):
                    old = filename
                    filename = os.path.dirname(filename)
                    if filename == old:
                        break
                else:
                    if filename[-4:] in ('.pyc', '.pyo'):
                        filename = filename[:-1]
                    yield filename

    mtimes = {}
    while 1:
        for filename in chain(iter_module_files(), extra_files or ()):
            try:
                mtime = os.stat(filename).st_mtime
            except OSError:
                continue

            old_time = mtimes.get(filename)
            if old_time is None:
                mtimes[filename] = mtime
                continue
            elif mtime > old_time:
                _log('info', ' * Detected change in %r, reloading' % filename)
                sys.exit(3)
        time.sleep(interval)


def restart_with_reloader():
    """Spawn a new Python interpreter with the same arguments as this one,
    but running the reloader thread.
    """
    while 1:
        _log('info', ' * Restarting with reloader...')
        args = [sys.executable] + sys.argv
        new_environ = os.environ.copy()
        new_environ['WERKZEUG_RUN_MAIN'] = 'true'

        # a weird bug on windows. sometimes unicode strings end up in the
        # environment and subprocess.call does not like this, encode them
        # to latin1 and continue.
        if os.name == 'nt':
            for key, value in new_environ.iteritems():
                if isinstance(value, unicode):
                    new_environ[key] = value.encode('iso-8859-1')

        exit_code = subprocess.call(args, env=new_environ)
        if exit_code != 3:
            return exit_code


def run_with_reloader(main_func, extra_files=None, interval=1):
    """Run the given function in an independent python interpreter."""
    if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
        thread.start_new_thread(main_func, ())
        try:
            reloader_loop(extra_files, interval)
        except KeyboardInterrupt:
            return
    try:
        sys.exit(restart_with_reloader())
    except KeyboardInterrupt:
        pass

其他提示

内置 reload() 功能可以为您做到这一点。此功能很可能是烧瓶对重新加载代码的作用的背后(在注意到它以某种方式在磁盘上发生了变化之后)。

问题 如何卸载(重新加载)Python模块? 有更多信息。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top