当uvicorn workers>1时,uvicorn和fastAPI与pyinstaller出现问题

2024-04-29 00:08:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我查过了 PyInstaller and FastAPI (maximum recursion depth exceeded)Pyinstaller-compiled Uvicorn server does not start correctly

FastAPI演示main.py

import uvicorn
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def root():
    return {"hello": "world"}

if __name__ == '__main__':
    uvicorn.run(app, host="0.0.0.0", port=58000, reload=False)

首先运行pyinstaller pyinstaller -F main.py --clean并在规范中添加hidden_imports

hidden_imports=[
                'uvicorn.logging',
                'uvicorn.loops',
                'uvicorn.loops.auto',
                'uvicorn.protocols',
                'uvicorn.protocols.http',
                'uvicorn.protocols.http.auto',
                'uvicorn.protocols.websockets',
                'uvicorn.protocols.websockets.auto',
                'uvicorn.lifespan',
                'uvicorn.lifespan.on',
            ]

它工作正常,但当workers大于1时,应用程序必须为字符串:

WARNING: You must pass the application as an import string to enable 'reload' or 'workers'.

因此,我改为:

if __name__ == '__main__':
    uvicorn.run("main:app", host="0.0.0.0", port=58000, reload=False, workers=2)

完成后,我运行了应用程序dist/main,它创建了许多应用程序,如下图所示,使用100%的CPU和100%的内存快速运行:

error message

适用于Python 3.8.3和pyinstaller 4.0


Tags: runnamepyimportapp应用程序autoif
2条回答

在我看来,这就像一个无限递归。我怀疑原因与main:app的自引用和一些将__name__设置为__main__的PyInstaller sys暗魔法有关

我建议将app移动到一个单独的模块中,并在uvicorn.run()中从该模块引用它:

# app.py
from fastapi import FastAPI


app = FastAPI()

@app.get("/")
def root():
    return {"hello": "world"}
# main.py
import uvicorn


if __name__ == "__main__":
    uvicorn.run("app:app", host="0.0.0.0", port=58000, reload=False, workers=2)

另外,不要忘记添加app.py作为PyInstaller的隐藏导入:

hidden_imports=[
    'uvicorn.logging',
    'uvicorn.loops',
    'uvicorn.loops.auto',
    'uvicorn.protocols',
    'uvicorn.protocols.http',
    'uvicorn.protocols.http.auto',
    'uvicorn.protocols.websockets',
    'uvicorn.protocols.websockets.auto',
    'uvicorn.lifespan',
    'uvicorn.lifespan.on',
    'app',
]

在开始时调用(在Windows上)mutiprocessing.freeze_support()很重要,请参见官方docs

import multiprocessing
...
...
...
if __name__ == '__main__':
    mutiprocessing.freeze_support()
    uvicorn.run("main:app", host="0.0.0.0", port=58000, reload=False, workers=2)

此外,可能需要添加模块main作为隐藏导入

相关问题 更多 >