我目前正在使用 Flask,但无法弄清楚调试机制是如何工作的。更准确地说,当我用我的应用程序保存 python 文件时,我不需要重新启动服务器,它会在我发出请求时自动加载。所以我的问题是正在运行的程序如何知道它已更改并响应该更改?
问问题
1563 次
2 回答
7
Flask 正在使用 Werkzug 的底层函数run_with_reloader
(在 serving.py
restart_with_reloader
reloader_loop
run_with_reloader
生成另一个 python 进程(再次运行 Werkzug 并使用您传递给第一个进程的所有相同参数),并且这个新进程使用该thread
模块生成一个新线程或子进程来运行您的服务器函数。然后它运行reloader_loop
并等待。
reloader_loop
只需遍历所有已导入的模块并获取它们的最后修改日期。然后以指定的时间间隔(默认为 1 秒)再次检查所有文件以查看它们是否已被修改。如果有,则当前运行的(从属)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
于 2010-12-22T22:43:15.610 回答
0
内置reload()
功能可以为您做到这一点。这个函数很可能是 Flask 重新加载代码的原因(在注意到它以某种方式在磁盘上发生了变化之后)。
问题如何卸载(重新加载)Python 模块?有更多关于这方面的信息。
于 2010-12-22T22:18:25.090 回答