現在Flaskで遊んでいますが、デバッグメカニズムがどのように機能しているかわかりません。より正確には、アプリケーションでPythonファイルを保存するときに、サーバーを再起動する必要はありません。リクエストを行うと、サーバーが自動的に読み込まれます。だから私の質問は、実行中のプログラムがそれが変更されたことをどのように認識し、その変更に応答するのかということです。
2 に答える
Flaskは、Werkzugの基礎となるrun_with_reloader
関数(にありますserving.py
)を使用しています...これ自体は、同じファイルで以前に作成され たrestart_with_reloader
and関数を使用しています。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
組み込みreload()
関数はあなたのためにこれを行うことができます。この関数は、Flaskがコードをリロードするために行うことの背後にある可能性があります(ディスク上で何らかの方法で変更されたことに気付いた後)。
質問Pythonモジュールをアンロード(リロード)するにはどうすればよいですか?これについての詳細があります。