企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
https://blog.zengrong.net/post/2632.html The Werkzeug reloader spawns a child process so that it can restart that process each time your code changes. Werkzeug is the library that supplies Flask with the development server when you call `app.run()`. See the [`restart_with_reloader()` function code](https://github.com/mitsuhiko/werkzeug/blob/49ee2786630a0307631f4184c3c58d56996cb2b4/werkzeug/_reloader.py#L90-L110); your script is run *again* with `subprocess.call()`. If you set `use_reloader` to `False` you'll see the behaviour go away, but then you also lose the reloading functionality: ~~~ app.run(port=4004, debug=config.DEBUG, host='0.0.0.0', use_reloader=False) ~~~ You can look for the `WERKZEUG_RUN_MAIN` environment variable if you wanted to detect when you are in the reloading child process: ~~~ if __name__ == '__main__': import os if os.environ.get('WERKZEUG_RUN_MAIN') == 'true': print '################### Restarting @ {} ###################'.format( datetime.utcnow()) app.run(port=4004, debug=config.DEBUG, host='0.0.0.0') ~~~ However, if you need to set up module globals, then you should instead use the [`@app.before_first_request` decorator](http://flask.pocoo.org/docs/0.10/api/#flask.Flask.before_first_request) on a function and have that function set up such globals. It'll be called just once after every reload when the first request comes in: ~~~ @app.before_first_request def before_first_request(): print '########### Restarted, first request @ {} ############'.format( datetime.utcnow()) ~~~ Do take into account that if you run this in a full-scale WSGI server that uses forking or new subprocesses to handle requests, that `before_first_request` handlers *may* be invoked for each new subprocess. * * * * * Flask 在 Debug 模式下启动的时候,会被初始化两次。看下面的代码: > from app import app > import time > if __name__ == '__main__': > print(time.time()) > app.run(port=5000, debug=True) 输出: > > 1492742262.002537 > * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) > * Restarting with stat > 1492742262.598912 > * Debugger is active! > * Debugger pin code: xxx-xxx-xxx 这将导致我们的某些需要在初始化时执行的方法被执行2次,这显然不是我们需要的结果。 出现这样的问题的原因是在开启 Debug 模式的时候,Werkzeug 默认会 [启动一个额外的进程](https://github.com/pallets/werkzeug/blob/0.12.1/werkzeug/_reloader.py#L105-L126) 来监控文件变化以方便重启进程。 要解决这个启动两次的问题,有这样几种方法: ## [](https://blog.zengrong.net/post/2632.html#1-取消自动重启 "1\. 取消自动重启")1\. 取消自动重启 在 Debug 模式下,为了方便调试,Flask 提供了当文件变化的时候自动重启实例的功能。关闭这个功能就可以避免初始化2次的情况。 > app.run(port=5000, debug=True, use_reloader=False) ## [](https://blog.zengrong.net/post/2632.html#2-判断-Werkzeug-主进程是否执行 "2\. 判断 Werkzeug 主进程是否执行")2\. 判断 Werkzeug 主进程是否执行 在 [restart_with_reloader function](https://github.com/pallets/werkzeug/blob/0.12.1/werkzeug/_reloader.py#L105-L126) 中,我们可以看到在新进程启动前,环境变量 `WEAKZEUG_RUN_MAIN`被置为 `'true'` : > new_environ['WERKZEUG_RUN_MAIN'] = 'true' 通过判断这个变量的值,我们就能保证在启动时仅执行一次: > if __name__ == '__main__': > import os > if os.environ.get('WERKZEUG_RUN_MAIN') == 'true': > print(time.time()) > app.run(port=5000, debug=config.DEBUG) ## [](https://blog.zengrong.net/post/2632.html#3-在第一次请求的时候执行 "3\. 在第一次请求的时候执行")3\. 在第一次请求的时候执行 使用 `before_first_request` 这个钩子,把执行放在 Flask 第一次收到请求的时候。这就避免了2次初始化的干扰。 > @app.before_first_request > def initialize(): > print(time.time()) ## [](https://blog.zengrong.net/post/2632.html#4-在需要请求的时候执行 "4\. 在需要请求的时候执行")4\. 在需要请求的时候执行 和“在第一次请求的时候执行”类似,使用一个开关变量,控制执行仅一次。把执行延迟到了应用逻辑层面。 (全文完) **参考:** * [Why does running the Flask dev server run itself twice?](http://stackoverflow.com/a/25504196/1542345) * [How to stop Flask from initialising twice in Debug Mode?](http://stackoverflow.com/a/9476701/1542345)