【问题标题】:uvicorn and fastAPI with pyinstaller problem when uvicorn workers>1当 uvicorn workers>1 时 uvicorn 和 fastAPI 与 pyinstaller 问题
【发布时间】:2021-04-02 21:22:40
【问题描述】:

我已经检查过了 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',
            ]

效果不错,但是worker大于1的时候app必须是字符串:

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

【问题讨论】:

    标签: python pyinstaller fastapi uvicorn


    【解决方案1】:

    在开始时调用(在 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 添加为隐藏导入。

    【讨论】:

    • 虽然官方文档说它“在 Windows 以外的任何操作系统上调用时都没有效果”,但它确实适用于我的情况:fastapi+uvicorn+pyinstaller+docker。没有 freeze_support,docker 容器会无限重启
    • 可以确认。 freeze_support 修复了 ubuntu20.04 (python3.8; fastapi+uvicorn+pyinstaller) 上的无限递归。
    【解决方案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',
    ]
    

    【讨论】:

      猜你喜欢
      • 2022-12-21
      • 2020-10-14
      • 2021-11-07
      • 2021-10-14
      • 2021-04-12
      • 2023-03-18
      • 2021-07-30
      • 2020-11-03
      • 2020-05-24
      相关资源
      最近更新 更多