我查过 PyInstaller 和 FastAPI(超出最大递归深度) 和 Pyinstaller编译的Uvicorn服务器无法正确启动
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% 内存:
适用于 Python 3.8.3 和 pyinstaller 4.0
一开始就调用(在Windows上)
mutiprocessing.freeze_support()
很重要,请参阅官方文档。
import multiprocessing
...
...
...
if __name__ == '__main__':
mutiprocessing.freeze_support()
uvicorn.run("main:app", host="0.0.0.0", port=58000, reload=False, workers=2)
此外,可能需要将模块
main
添加为隐藏导入。
对我来说这看起来像是无限递归。我怀疑原因与
main:app
处的自引用和一些 PyInstaller sys
黑魔法将 __name__
设置为 __main__
有关。
我建议将
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',
]
在 Attila Viniczai 发布的上述第二个解决方案中, 请额外添加一行,这样它将停止无限递归问题。
# main.py
import uvicorn
import multiprocessing
if __name__ == "__main__":
multiprocessing.freeze_support()
uvicorn.run("app:app", host="0.0.0.0", port=58000, reload=False, workers=2)