如何用Pandas apply()高效调用Web服务并控制并发请求数
控制Web服务并发请求填充Pandas列的解决方案
一、Pandas apply()的局限性
Pandas的apply()方法是单线程串行执行的,无法直接控制并发请求数。如果用apply处理,所有Web请求会逐个发送,既没法利用并发提升效率,也满足不了你最多3个并发的限制要求,必须换用其他方案。
二、推荐方案:用ThreadPoolExecutor控制并发
调用Web服务属于IO密集型任务,使用线程池是最优选择。concurrent.futures.ThreadPoolExecutor可以直接指定最大并发数(这里设为3),既符合服务限制,又能显著提升处理速度。
代码示例
import pandas as pd import requests from concurrent.futures import ThreadPoolExecutor # 封装Web请求函数,增加超时和异常处理 def get_status(id_val): url = f'http://www.example.com/?id={id_val}' try: # 设置超时,避免请求挂起 response = requests.get(url, timeout=10) response.raise_for_status() # 主动抛出HTTP错误 return response.text.strip() except requests.exceptions.RequestException as e: # 处理请求异常,返回标记值 print(f"请求id={id_val}失败: {str(e)}") return 'Error' # 主逻辑 df = pd.DataFrame([['1', 'Jane'], ['2', 'John'], ['3', 'Bob'], ['4', 'Alice']], columns=['id', 'Name']) # 用ThreadPoolExecutor控制3个并发请求 with ThreadPoolExecutor(max_workers=3) as executor: # 批量提交id列的请求,获取结果列表 status_list = list(executor.map(get_status, df['id'])) # 将结果赋值给新列 df['Status'] = status_list print(df)
三、备选方案:分块循环处理
如果不想用线程池,也可以手动分块,每次处理3条记录,适合对并发逻辑要求简单的场景:
代码示例
import pandas as pd import requests def get_status(id_val): url = f'http://www.example.com/?id={id_val}' try: response = requests.get(url, timeout=10) response.raise_for_status() return response.text.strip() except requests.exceptions.RequestException as e: print(f"请求id={id_val}失败: {str(e)}") return 'Error' df = pd.DataFrame([['1', 'Jane'], ['2', 'John'], ['3', 'Bob'], ['4', 'Alice']], columns=['id', 'Name']) df['Status'] = '' # 按每3条分块处理 chunk_size = 3 for i in range(0, len(df), chunk_size): chunk = df.iloc[i:i+chunk_size] # 对当前块的id逐个发送请求 for idx in chunk.index: df.loc[idx, 'Status'] = get_status(df.loc[idx, 'id']) print(df)
四、关键注意事项
- 超时设置:必须给
requests.get()加上timeout参数,避免单个请求卡住导致整个流程停滞。 - 异常处理:捕获连接失败、HTTP错误等异常,避免单个请求失败终止整个任务。
- 请求规范:如果Web服务需要认证或特定请求头,要通过
requests.get()的headers参数传递。 - 返回值解析:如果服务返回JSON格式数据,改用
response.json()解析,确保结果符合预期格式。
内容的提问来源于stack exchange,提问作者Wilmar
相关产品推荐
相关产品推荐

