ThreadPoolExecutor处理7000个客户端过慢,如何优化提速?
批量API调用性能优化方案
现有代码实现
获取子客户端信息的核心函数
def get_subclient_info(client_id: int) -> list: subclient_url = "http://{0}/SearchSvc/CVWebService.svc/Subclient?clientId={1}".format(vault_url, client_id) subclient_info = { 'client_id': None, 'client_name': None, 'subclient_id': None, 'subclient_name': None, 'application_id': None, 'application_name': None, 'instanceName': None, 'subclient_backup_enabled': None } headers = { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authtoken': '{0}'.format(access_token) } response = requests.request("GET", subclient_url, headers=headers, data=payload) response_json = json.loads(response.text) # print(response_json) subclient_info_list = [] sub_clients = response_json.get('subClientProperties', {}) for s in sub_clients: sub_client_data = { "client_id": client_id, "client_name": s["subClientEntity"]["clientName"], "subclient_id": s["subClientEntity"]["subclientId"], "subclient_name": s["subClientEntity"]["subclientName"], "application_id": s["subClientEntity"]["applicationId"], "application_name": s["subClientEntity"]["appName"], "subclient_backup_enabled": get_subclient_backup_status(s["subClientEntity"]["subclientId"]), "instanceName": get_subclient_InstanceName(s["subClientEntity"]["subclientId"]) } subclient_info_list.append(sub_client_data) return subclient_info_list
线程池调用逻辑
import requests import concurrent.futures subclient_entities = {} with concurrent.futures.ThreadPoolExecutor() as executor: futures_sub = [executor.submit(get_subclient_info, client_id) for client_id in list_clientid] for client_id, future_s in zip(list_clientid, concurrent.futures.as_completed(futures_sub)): result = future_s.result() subclient_entities[client_id] = result
当前困境
处理7000个客户端时,耗时超过1小时。先后试过普通循环、列表推导式,最后换成ThreadPoolExecutor后速度有提升,但离30分钟的目标还有差距,需要进一步优化。
具体优化建议
- 调大线程池并发数:默认的线程数是CPU核心数的5倍,对于API调用这种IO密集型任务来说远远不够。可以手动设置
max_workers参数,比如ThreadPoolExecutor(max_workers=50),甚至根据API的限流情况调到100左右(注意别触发对方的反限流机制)。 - 复用HTTP连接:现在每次请求都新建TCP连接,握手和断开的开销很大。用
requests.Session()来复用连接,把Session实例提前创建好,在函数里用session.get()代替requests.request(),能大幅减少网络耗时。 - 尝试批量查询API:去查一下你调用的这个API是否支持一次性传入多个
client_id,如果能批量请求,直接把7000个分成几批查,请求次数从7000降到几十,性能提升会非常明显。 - 优化额外的API调用:
get_subclient_backup_status和get_subclient_InstanceName这两个函数看起来是每个子客户端都要单独发请求,这会产生大量额外的网络请求。要么看看能不能在主请求里顺便拿到这些数据,要么把所有需要查的subclient_id收集起来批量查询,别单个请求。 - 换成异步IO框架:用
aiohttp代替requests,配合asyncio做异步请求,异步IO在处理大量网络等待时比线程池更高效,没有线程切换的开销,能进一步提升并发量。 - 添加超时和重试:给请求加个合理的超时时间,比如
timeout=10,避免某个慢请求卡住整个流程;同时给失败的请求加重试机制(比如用tenacity库),减少因网络波动导致的重试等待。 - 简化JSON解析:
requests自带的response.json()比手动json.loads(response.text)更高效,直接替换掉能省一点解析时间。 - 提前生成静态数据:
headers里的内容每次调用函数都重新生成,其实可以把headers移到函数外面,只生成一次,避免重复计算。
内容的提问来源于stack exchange,提问作者anormaluser
相关产品推荐
相关产品推荐

