Django views用requests发起多接口请求如何优化代码效率与灵活性
代码优化方案
你当前的冗余代码本质是把固定的请求执行逻辑和动态的接口配置写死耦合了,优化分两步走,先消弭重复代码,再解决串行请求的效率问题。
第一步:抽离公共逻辑,实现配置与代码分离
所有IEX接口的公共部分(域名、鉴权token、请求发送、响应解析逻辑)完全不需要重复编写,只需要把每个接口的差异部分(路径、自定义参数、对应模板变量名)抽成统一配置即可。
先把公共常量定义在视图函数外层,避免每次请求进来重复初始化:
import requests from concurrent.futures import ThreadPoolExecutor, as_completed import environ env = environ.Env() environ.Env.read_env() # 公共固定配置 IEX_API_BASE = "https://cloud.iexapis.com/v1" IEX_TOKEN = env("API_IEX") # 接口配置列表,格式为:(模板变量名, 接口路径模板, 接口专属查询参数) # 后续新增/删除/修改接口,只需要调整这个列表即可,不需要改动核心请求逻辑 API_ENDPOINTS = [ ("api", "/stock/{ticker}/quote", {"displayPercent": "true"}), ("api2", "/anything/anything/{ticker}", {"anything": "true"}), ("api3", "/anything/anything2/{ticker}", {"anything2": "true"}), ]
再抽一个通用的单接口请求函数,只负责处理单个接口的请求、解析、异常兜底:
def fetch_single_iex_endpoint(ticker: str, endpoint_config: tuple) -> tuple: var_name, path_template, extra_params = endpoint_config # 拼接完整请求参数 request_path = path_template.format(ticker=ticker) request_params = {"token": IEX_TOKEN, **extra_params} # 记得加超时,避免单个接口卡死拖垮整个请求 resp = requests.get( f"{IEX_API_BASE}{request_path}", params=request_params, timeout=8 ) resp.raise_for_status() return var_name, resp.json()
第二步:用并发请求替代串行调用,提升执行效率
你原来的写法是按顺序逐个请求接口,10-15个接口的总耗时是所有接口耗时的总和,用线程池做并发请求的话,总耗时基本等于最慢的单个接口的耗时,IO密集场景下性能提升非常明显。
优化后的视图函数逻辑非常简洁:
def stocks(request): input_ticker = request.POST["ticker"] template_context = {} # 线程池并发拉取所有接口数据,IO密集场景用线程池开销极小 with ThreadPoolExecutor(max_workers=10) as executor: # 批量提交所有请求任务 task_list = [ executor.submit(fetch_single_iex_endpoint, input_ticker, endpoint) for endpoint in API_ENDPOINTS ] # 按任务完成顺序收集结果 for task in as_completed(task_list): try: var_name, parsed_data = task.result() template_context[var_name] = parsed_data except Exception as e: # 单个接口请求失败的兜底逻辑,可根据业务需求调整 template_context[var_name] = None # 可自行加日志记录错误信息,方便排查问题 return render(request, "result_api.html", template_context)
额外优化建议
- 所有接口配置统一管理后,后续要加新接口只需要在
API_ENDPOINTS列表里加一行配置即可,不需要写重复的请求、解析、传值代码 - 不要在这个场景下用进程池,HTTP请求属于IO密集型操作,线程池的性能足够,资源开销也远小于进程池
- 如果后续接口量继续增长,可以把
API_ENDPOINTS挪到单独的配置文件(比如Django的settings里),进一步解耦配置和业务逻辑 - 如果部分接口不是每次页面加载都需要拉取,可以在接口配置里加开关字段,按需提交请求即可,进一步减少不必要的请求开销
内容的提问来源于stack exchange,提问作者micho
相关产品推荐
相关产品推荐

