将 Flask 与需要并行化到多个内核的 CPU 绑定请求一起使用

Using Flask with CPU-bound requests that need to be parallelized onto multiple cores

我工作的一位计算科学家编写了一个程序,该程序使用由 scikit-learn 构建的机器学习模型对输入进行评分。我的任务是让这个 ML 评分器作为微服务可用。

所以我用 Flask 写了几行代码来完成这个。任务完成!

嗯,不完全是。由于此服务有时会受到严重打击,因此它需要能够并行处理多个请求。 (即,在多核上。我们的服务器上有大约 20 个。)我可以通过大约十分钟的努力实现的解决方案是在不同的端口上启动十个或二十个这样的小型 REST 服务器并轮询它们使用 nginx 作为反向代理。

虽然这会很好地工作,但我敢肯定,我认为让一个 Python 服务器处理所有请求比让二十个 Python 服务器更优雅。所以我开始阅读 WSGI 和 uWSGI 以及其他一些东西。但是我通过所有这些阅读和网上冲浪所取得的成就最终变得非常混乱。

所以我会在这里问而不是试图自己解决这个问题:我应该坚持使用我上面描述的蛮力方法吗?还是我可以做一些更好的事情?

但是,如果做某事 "better" 需要花费数天的时间来浏览难以理解的文档、进行令人沮丧的实验并拔掉我所有的头发,那么我宁愿坚持使用愚蠢的蛮力我已经理解并且我肯定会奏效的方法。

谢谢。

我建议为此迁移 FastAPI。它明显更快,非常易于使用(特别是如果您从 Flask 迁移),并且被很多人用于 ML 推理。

FastAPI 使用 python 中较新的异步功能,这使得它可以使用相同数量的资源处理更多的请求。

您还可以将现有的 docker 容器用于 flask 或 fastapi,而不是自行配置。

按照 tedivm 的建议,我使用 FastAPI 和 uvicorn 实现了一个可行的解决方案。

这是一个名为 test_fast_api.py 的示例小服务器程序。它响应 GET 和 POST 请求(POST 请求应该在 JSON 中)并且响应在 JSON:

from typing import List
from fastapi import FastAPI

app = FastAPI()

@app.get("/score/{seq}")
async def score(seq: str):
    return len(seq)

@app.get("/scores/{seqs}")
async def scores(seqs: str):
    return [len(seq) for seq in seqs.split(",")]

@app.post("/scores")
async def scores_post(seqs: List[str]):
    return [len(seq) for seq in seqs]

此服务可以由 10 个进程提供服务,如下所示:

$ uvicorn --workers 10 --port 12345 test_fast_api:app

如果此服务实际上是 CPU 绑定的,运行 使用 10 个进程将允许它充分利用 10 个 CPU 核心。