首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >FastAPI返回大量JSON数据的速度非常慢

FastAPI返回大量JSON数据的速度非常慢
EN

Stack Overflow用户
提问于 2022-08-31 21:51:59
回答 2查看 1.2K关注 0票数 2

我有一个FastAPI GET端点,它返回大量JSON数据(~160,000行和45列)。毫不奇怪,使用json.dumps()返回数据的速度非常慢。我首先使用json.loads()从文件中读取数据,然后根据输入的参数对其进行过滤。是否有比使用return data更快地将数据返回给用户的方法?在目前的状态下,这需要近一分钟的时间。

我的代码当前如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# helper function to parse parquet file (where data is stored)
def parse_parquet(file_path):
    df = pd.read_parquet(file_path)
    result = df.to_json(orient = 'records')
    parsed = json.loads(result)
    return parsed
    

@app.get('/endpoint')
# has several more parameters
async def some_function(year = int | None = None, id = str | None = None):
    if year is None:
        data = parse_parquet(f'path/{year}_data.parquet')
    # no year
    if year is not None:
        data = parse_parquet(f'path/all_data.parquet')
    if id is not None:
        data = [d for d in data if d['id'] == id]
    return data
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-09-02 00:55:37

响应如此缓慢的原因之一是,在您的parse_parquet()方法中,首先将文件转换为JSON (使用df.to_json()),然后转换为字典(使用json.loads()),最后再转换为JSON,作为FastAPI,在幕后使用jsonable_encoder将返回的值转化为与JSON兼容的数据,然后使用Python json.dumps()来序列化对象--这个过程非常慢(更多细节见这个答案 )。

正如@MatsLindh在注释部分中所建议的那样,您可以使用替代的JSON编码器,例如奥尔森尤约森,这确实会加快进程,而不是让FastAPI使用jsonable_encoder,然后让标准json.dumps()将数据转换为JSON。然而,,使用熊猫to_json()并直接重新定制Response --正如这个答案-seems的选项1 (Update 2)所描述的那样,它是性能最好的解决方案。您可以使用下面给出的代码--它使用班级-to来比较所有可用解决方案的响应时间。

使用您自己的拼花文件或下面的代码创建一个由160 K行和45列组成的样例拼花文件。

create_parquet.py

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import pandas as pd
import numpy as np

columns = ['C' + str(i) for i in range(1, 46)]
df = pd.DataFrame(data=np.random.randint(99999, 99999999, size=(160000,45)),columns=columns)
df.to_parquet('data.parquet')

运行下面的FastAPI应用程序,并分别访问每个端点,以检查完成将数据加载和转换为JSON过程所需的时间。

app.py

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from fastapi import FastAPI, APIRouter, Response, Request
from fastapi.routing import APIRoute
from typing import Callable
import pandas as pd
import json
import time
import ujson
import orjson


class TimedRoute(APIRoute):
    def get_route_handler(self) -> Callable:
        original_route_handler = super().get_route_handler()

        async def custom_route_handler(request: Request) -> Response:
            before = time.time()
            response: Response = await original_route_handler(request)
            duration = time.time() - before
            response.headers["Response-Time"] = str(duration)
            print(f"route duration: {duration}")
            return response

        return custom_route_handler

app = FastAPI()
router = APIRouter(route_class=TimedRoute)

@router.get("/defaultFastAPIencoder")
def get_data_default():
    df = pd.read_parquet('data.parquet')   
    return df.to_dict(orient="records")
    
@router.get("/orjson")
def get_data_orjson():
    df = pd.read_parquet('data.parquet')
    return Response(orjson.dumps(df.to_dict(orient='records')), media_type="application/json")

@router.get("/ujson")
def get_data_ujson():
    df = pd.read_parquet('data.parquet')   
    return Response(ujson.dumps(df.to_dict(orient='records')), media_type="application/json")

# Preferable way to do it  
@router.get("/pandasJSON")
def get_data_pandasJSON():
    df = pd.read_parquet('data.parquet')   
    return Response(df.to_json(orient="records"), media_type="application/json")  

app.include_router(router)

尽管使用上面的/pandasJSON响应时间相当快(这是最好的方法),但在浏览器上显示数据时可能会遇到一些延迟。然而,这与服务器端无关,而与客户端有关,因为浏览器试图显示大量数据。如果您不想显示数据,而是让用户将数据下载到他们的设备(这会快得多),您可以使用Content-Disposition参数将Response头设置为Response,并传递一个filename,指示浏览器应该下载该文件。有关更多细节,请查看这个答案这个答案

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@router.get("/download")
def get_data():
    df = pd.read_parquet('data.parquet')
    headers = {'Content-Disposition': 'attachment; filename="data.json"'}
    return Response(df.to_json(orient="records"), headers=headers, media_type='application/json')

我还应该提到,有一个名为Dask的库,它可以处理大型数据集,如这里所描述的那样,以防您必须处理大量记录,并且要花费太长时间才能完成该过程。与Pandas类似,您可以使用.read_parquet()方法读取文件。由于Dask似乎没有提供等效的.to_json()方法,所以可以使用df.compute()将Dask DataFrame转换为Pandas DataFrame,然后使用Pandas df.to_json()将DataFrame转换为JSON字符串,并按上面所示返回。

票数 4
EN

Stack Overflow用户

发布于 2022-08-31 22:53:05

我猜在您的情况下,json.loads(result)将返回一个dict数据类型,并且您正在过滤dict数据类型。您可以将dict数据类型发送为JSON,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from fastapi.responses import JSONResponse

@app.get('/endpoint')
# has several more parameters
async def some_function(year = int | None = None, id = str | None = None):
    if year is None:
        data = parse_parquet(f'path/{year}_data.parquet')
    # no year
    if year is not None:
        data = parse_parquet(f'path/all_data.parquet')
    if id is not None:
        data = [d for d in data if d['id'] == id]
    return JSONResponse(content=json_compatible_item_data)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73564771

复制
相关文章
Contact Manager Web API 示例[2] Web API Routing
联系人管理器web API是一个Asp.net web api示例程序,演示了通过ASP.NET Web API 公开联系信息,并允许您添加和删除联系人,示例地址http://code.msdn.microsoft.com/Contact-Manager-Web-API-0e8e373d。 Contact Manager Web API 示例[1]CRUD 操作 已经做了一个基本的介绍,本文主要介绍Web API Routing。 如果你已经熟悉 ASP.NET MVC,你会发现 Web API Routi
张善友
2018/01/22
9740
Contact Manager Web API 示例[2] Web API Routing
联系人管理器web API是一个Asp.net web api示例程序,演示了通过ASP.NET Web API 公开联系信息,并允许您添加和删除联系人,示例地址http://code.msdn.microsoft.com/Contact-Manager-Web-API-0e8e373d。 Contact Manager Web API 示例[1]CRUD 操作 已经做了一个基本的介绍,本文主要介绍Web API Routing。 如果你已经熟悉 ASP.NET MVC,你会发现 Web API Routi
张善友
2018/01/22
1K0
使用OAuth 2.0访问谷歌的API
谷歌的API使用的OAuth 2.0协议进行身份验证和授权。谷歌支持常见的OAuth 2.0场景,如那些Web服务器,安装,和客户端应用程序。
拿我格子衫来
2022/01/24
4.6K0
使用OAuth 2.0访问谷歌的API
Contact Manager Web API 示例[1]CRUD 操作
联系人管理器web API是一个Asp.net web api示例程序,演示了通过ASP.NET Web API 公开联系信息,并允许您添加和删除联系人,示例地址http://code.msdn.microsoft.com/Contact-Manager-Web-API-0e8e373d . 下面的文章以这个示例讲解ASP.NET Web API的各方面知识: 1、CRUD操作: CURD 是 "Create, Read, Update, Delete" (新增、读取、更新、删除) 的简写,这四个动作是数据
张善友
2018/01/22
9290
Contact Manager Web API 示例[4] 异常处理(Exception Handling)
联系人管理器web API是一个Asp.net web api示例程序,演示了通过ASP.NET Web API 公开联系信息,并允许您添加和删除联系人,示例地址http://code.msdn.microsoft.com/Contact-Manager-Web-API-0e8e373d。 Contact Manager Web API 示例[1]CRUD 操作 已经做了一个基本的介绍, Contact Manager Web API 示例[2] Web API Routing 介绍Web API Rout
张善友
2018/01/22
8190
[CORS:跨域资源共享] 同源策略与JSONP
Web API普遍采用面向资源的REST架构,将浏览器最终执行上下文的JavaScript应用Web API消费者的重要组成部分。“同源策略”限制了JavaScript的跨站点调用,这必然导致Web API不能垮域提供资源。如果Web API仅限于为“同源客户端”提供资源,那么它都对不起自己的名字,因为Web本身是一个开放的协议。那么ASP.NET Web API通过怎样的方式来实现跨域资源共享呢? 同源策略 浏览器是访问Internet的工具,也是客户端应用的宿主,它为客户端应用提供一个寄宿和运行的环境。
蒋金楠
2018/01/15
1.1K0
[CORS:跨域资源共享] 同源策略与JSONP
使用谷歌标准api时protobuf生成遇到的问题
在vscode时新增proto文件时,按下sr会出现一个快捷生成CRUD服务的例子
天地一小儒
2022/12/28
1.9K0
使用谷歌标准api时protobuf生成遇到的问题
API,打开“共享之门”的最好钥匙
我们经常听到开发人员讨论API。API与APP一词看上去很相似,对于APP我们很熟悉,即是应用程序Application的缩写,随着智能手机的普及这一词成了手机软件的代称。但是API又是什么呢? AP
BestSDK
2018/03/01
1K0
API,打开“共享之门”的最好钥匙
C#调用腾讯云文本翻译API,使用V3签名报错。
"Error":{"Code":"AuthFailure.SignatureFailure","Message":"The provided credentials could not be validated. Please check your signature is correct."
用户9018380
2021/09/20
2K0
Contact Manager Web API 示例[3] 分页和查询(Paging and Querying)
联系人管理器web API是一个Asp.net web api示例程序,演示了通过ASP.NET Web API 公开联系信息,并允许您添加和删除联系人,示例地址http://code.msdn.microsoft.com/Contact-Manager-Web-API-0e8e373d。 Contact Manager Web API 示例[1]CRUD 操作 已经做了一个基本的介绍, Contact Manager Web API 示例[2] Web API Routing 介绍Web API Rout
张善友
2018/01/22
1.4K0
点击加载更多

相似问题

List vs ArrayList vs Dictionary vs Hashtable vs Stack vs Queue?

30

innerText vs innerHTML vs label vs text vs textContent vs outerText

665

.c vs .cc vs .cpp vs .hpp vs .h vs .cxx

64

Exec vs ExecWait vs ExecShell vs nsExec::Exec vs nsExec::ExecToLog vs nsExec::ExecToStack vs ExecDos vs ExeCmd

25

bundler vs RVM vs gem vs RubyGems vs gemsets vs system ruby

20
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文