为什么运行Flask开发服务器会自行运行两次?

时间:2014-08-26 10:58:15

标签: python flask

我正在使用Flask开发网站,在开发过程中,我使用以下文件运行烧瓶:

#!/usr/bin/env python
from datetime import datetime
from app import app
import config

if __name__ == '__main__':
    print '################### Restarting @', datetime.utcnow(), '###################'
    app.run(port=4004, debug=config.DEBUG, host='0.0.0.0')

当我启动服务器时,或者由于文件已更新而自动重启时,它总是显示两次打印行:

################### Restarting @ 2014-08-26 10:51:49.167062 ###################
################### Restarting @ 2014-08-26 10:51:49.607096 ###################

虽然这不是一个真正的问题(其余部分按预期工作),但我只是想知道它为什么会这样?有什么想法吗?

7 个答案:

答案 0 :(得分:111)

Werkzeug重新加载器会生成一个子进程,以便每次代码更改时都可以重新启动该进程。当您致电app.run()时,Werkzeug是向Flask提供开发服务器的库。

restart_with_reloader() function code;您的脚本将使用subprocess.call()再次运行

如果您将use_reloader设置为False,您会看到该行为消失,但您也会失去重新加载功能:

app.run(port=4004, debug=config.DEBUG, host='0.0.0.0', use_reloader=False)

您也可以在使用flask run命令时禁用重新加载器:

FLASK_DEBUG=1 flask run --no-reload

如果要检测何时处于重新加载子进程中,可以查找WERKZEUG_RUN_MAIN环境变量:

import os
if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
    print '################### Restarting @ {} ###################'.format(
        datetime.utcnow())

但是,如果你需要设置模块全局变量,那么你应该在函数上使用@app.before_first_request decorator并让该函数设置这样的全局变量。当第一个请求进入时,它会在每次重新加载后被调用一次:

@app.before_first_request
def before_first_request():
    print '########### Restarted, first request @ {} ############'.format(
        datetime.utcnow())

请注意,如果在使用分叉或新子进程处理请求的完整WSGI服务器中运行此服务器,则可以为每个新子进程调用before_first_request个处理程序

答案 1 :(得分:8)

如果您使用的是现代flask run命令,则不会使用app.run的任何选项。要完全禁用重新加载器,请传递--no-reload

FLASK_DEBUG=1 flask run --no-reload

此外,__name__ == '__main__'永远不会成立,因为应用程序不会直接执行。使用Martijn's answer中的相同提示,但不包含__main__块。

if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
    # do something only once, before the reloader

if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
    # do something each reload

答案 2 :(得分:6)

我遇到了同样的问题,我通过将app.debug设置为False来解决这个问题。将其设置为True会导致我的__name__ == "__main__"被调用两次。

(我会将此作为评论发布,但我没有足够的代表。作为答案发布,希望它可以帮助其他人)

答案 3 :(得分:1)

我正在使用插件 - python-dotenv 我会把它放在我的配置文件中 - .flaskenv:

FLASK_RUN_RELOAD=False

这将避免我的烧瓶运行两次。

答案 4 :(得分:0)

Flask应用程序运行两次的可能原因之一是在Heroku上配置了WEB_CONCURRENCY。要设置为一个,可以在控制台中编写 heroku config:set WEB_CONCURRENCY=1

答案 5 :(得分:0)

从Flask 0.11开始,建议使用flask run而不是python application.py运行您的应用。使用后者可能会导致您的代码运行两次。

As stated here

  

...从Flask 0.11开始,建议使用长瓶法。这样做的原因是,由于重载机制是如何工作的,所以存在一些奇怪的副作用(例如两次执行某些代码...)

答案 6 :(得分:-1)

我有同样的问题。我通过修改我的main并将use_reloader = False插入其中来解决了它。如果有人在寻找解决此问题的方法,那么下面的代码将帮助您入门,但是您将无法自动检测到代码更改并重新启动应用程序,因此该功能将不起作用。每次编辑代码后,您都必须手动停止并重新启动应用程序。

Private Function CreateFolder(ByVal sPath As String) As Boolean
'by Patrick Honorez - www.idevlop.com
'checks for existence of a folder and create it at once, if required
'returns False if folder does not exist and could NOT be created, True otherwise
'sample usage: If CreateFolder("C:\toto\test\test") Then debug.print "OK"
'updated 20130422 to handle UNC paths correctly ("\\MyServer\MyShare\MyFolder")

    Dim fs As Object
    Dim FolderArray
    Dim Folder As String, i As Integer, sShare As String

    If Right(sPath, 1) = "\" Then sPath = Left(sPath, Len(sPath) - 1)
    Set fs = CreateObject("Scripting.FileSystemObject")
    'UNC path ? change 3 "\" into 3 "@"
    If sPath Like "\\*\*" Then
        sPath = Replace(sPath, "\", "@", 1, 3)
    End If
    'now split
    FolderArray = Split(sPath, "\")
    'then set back the @ into \ in item 0 of array
    FolderArray(0) = Replace(FolderArray(0), "@", "\", 1, 3)
    On Error GoTo hell
    'start from root to end, creating what needs to be
    For i = 0 To UBound(FolderArray) Step 1
        Folder = Folder & FolderArray(i) & "\"
        If Not fs.FolderExists(Folder) Then
            fs.CreateFolder (Folder)
        End If
    Next
    CreateFolder = True
hell:
End Function