Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/codeigniter/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 服务于ML模型的FastAPI应用程序是否有阻塞代码?_Python_Async Await_Gunicorn_Fastapi_Uvicorn - Fatal编程技术网

Python 服务于ML模型的FastAPI应用程序是否有阻塞代码?

Python 服务于ML模型的FastAPI应用程序是否有阻塞代码?,python,async-await,gunicorn,fastapi,uvicorn,Python,Async Await,Gunicorn,Fastapi,Uvicorn,我们有一个装有烧瓶的ML模型。使用Gatling()对烧瓶应用进行负载测试,导致性能非常低。它无法每秒处理大量请求。因此,我们转向了FastAPI 用uvicorn或gunicorn在Docker容器中本地提供它效果很好。但是,我们注意到应用程序在几分钟内没有响应: 在这幅图中,您可以看到应用程序以“批处理”方式响应。在Kubernetes集群中服务我们的应用程序会导致容器重新启动,因为负责的容器不会成功完成就绪性/活动性探测 这个问题我们已经提过了。然而,我认为我们不会在那里得到答案。我们认为

我们有一个装有烧瓶的ML模型。使用Gatling()对烧瓶应用进行负载测试,导致性能非常低。它无法每秒处理大量请求。因此,我们转向了FastAPI

用uvicorn或gunicorn在Docker容器中本地提供它效果很好。但是,我们注意到应用程序在几分钟内没有响应:

在这幅图中,您可以看到应用程序以“批处理”方式响应。在Kubernetes集群中服务我们的应用程序会导致容器重新启动,因为负责的容器不会成功完成就绪性/活动性探测

这个问题我们已经提过了。然而,我认为我们不会在那里得到答案。我们认为这可能是因为我们编写的代码阻塞了主线程,因此我们的FastAPI应用程序在几分钟内不会响应

应用程序终结点的代码段:

async def verify_client(token: str):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        return jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM], audience=AUDIENCE)
    except JWTError:
        raise credentials_exception


@app.post("/score", response_model=cluster_api_models.Response_Model)
async def score(request: cluster_api_models.Request_Model, token: str = Depends(oauth2_scheme)):
    logger.info("Token: {0}".format(token))
    await verify_client(token)
    result = await do_score(request)
    return result
wait do_score(request)
包含所有预处理和预测代码。它使用gensim fasttext模型创建文档向量,并使用scikit learn K-Means模型
do_score()
是用
async def do_score(请求)
定义的。从一开始,我们认为这足以使我们的应用程序异步。然而,它看起来不像。它仍在按顺序处理,而且几分钟内没有响应。该方法还包括一个嵌套的for循环O(n²)。。。不确定这是否也会导致代码阻塞


我希望提供的信息足以开始。如果你需要更多关于代码的信息,请告诉我。我需要更改一些代码的变量名。提前非常感谢

当然,如果您的应用程序不是完全异步的,那么会有一些东西阻止您的应用程序,异步只是一个花哨的关键字

即使您使用
async def
定义了一个函数,如果它在下面做了一些阻塞,它也会阻塞应用程序的整个执行。你不相信吗?测试一下

@app.get(“/dummy”)
异步def dummy():
时间。睡眠(5)
让我们向它发送3个并发请求

for _ in {1..3}; do curl http://127.0.0.1:8000/dummy &; done
这将需要+15秒

让我们深入探讨一下,我说过async def只是声明协同路由的一种奇特语法,为什么?看

async def
函数始终是协程,即使它们不包含
wait
表达式

为什么这很重要? 当您定义一个协同程序时,使用
wait
语法,您将事件循环说成继续进行,它会这样做,它会切换到另一个协同程序并运行它

有什么区别? 基本上,协同程序不等待结果,它只是继续进行。但是当你定义一个普通函数时,它当然会等待它的执行

既然我们都知道它会阻塞,你能做什么?
您可能希望使用像芹菜这样的作业/任务队列库。

这里的正确答案是使用非异步路由定义。FastAPI说明,任何包含同步代码的路由都应该放在这些类型的路由中,这样它就可以将代码放在自己的内部线程池中,从而创建一个伪异步路由

@app.post(“/score”,response\u model=cluster\u api\u models.response\u model)
def分数(请求:集群\ api \模型。请求\模型,令牌:str=Depends(oauth2 \方案)):
logger.info(“令牌:{0}”.format(令牌))
验证\u客户端(令牌)
结果=do_分数(请求)
返回结果
这里有一个指向我引用的fastapi文档的链接


非常感谢您的快速回答。我们认为FastAPI将负责创建作业/任务队列。我想我们完全错了。因此,FastAPI应用程序的每个端点(活动性/就绪性检查)和每个函数都需要芹菜来处理?更新:我刚刚阅读了FastAPI中的背景任务。它建议将其用于小任务或需要访问在同一FastAPI应用程序中创建的变量的用例。因为我们使用的是一个相当大的文本模型,芹菜可能不是一个选项。将更新,什么对我们有效。在我们的情况下,我们有大约需要3-5分钟的模型和20秒的小任务,但我们通过设置优先级来为所有任务使用芹菜,这是我不建议
背景任务的原因。这里面有很多问题。下面是最常见的方法,您如何确保芹菜(我真的不反对这个选项),可以访问FastAPI应用程序中加载的模型,还是在每个请求中加载您的模型?通常执行方法
do_score(request)
的时间约为500毫秒。您能定义正确的答案吗?是什么使我的答案不正确?我已经在FastAPI社区呆了很长时间,我知道一些极端情况,有一些大问题,比如,从长远来看,会导致内存泄漏,在线程池中运行一个需要约500毫秒的函数是不好的。如果您的函数需要
1s>ns>5s。
那么您可以将其用于
>5s
您应该进行其他操作。感谢链接这些问题,我没有发现任何内存泄漏。因此,我可能应该说,公认的答案忽略了更简单的解决方案(非异步路由defs),它是通过FastAPI记录和支持的。我想我的答案确实定义了正确答案的含义。它遗漏了什么?