Python优化服务器GET请求耗时:多线程集成实现咨询
优化批量GET请求:从单线程到多线程提速
你的问题很典型——单线程处理网络请求时,大部分时间都在等待服务器响应,完全浪费了CPU的空闲时间。用多线程可以让多个请求同时发送,把等待时间利用起来,轻松把耗时从17秒压到5秒以内。下面我直接给你改造后的代码,再一步步解释怎么集成到你的现有逻辑里:
基础多线程实现(直接替换你的代码)
首先,我们用Python标准库的concurrent.futures.ThreadPoolExecutor来管理线程池,它比手动写线程逻辑简单太多,而且安全可靠:
import pandas as pd import requests from concurrent.futures import ThreadPoolExecutor auth_token = 'Wy' df = pd.read_csv('/instaurls.csv') # 把原来循环里的请求逻辑封装成单独函数 def fetch_ethnicity(url): try: # 这里用params参数自动处理URL编码,比字符串拼接更安全 resp = requests.get( 'http://predict/ethnicity', params={'auth_token': auth_token, 'url': url}, timeout=5 # 设置5秒超时,避免某个请求卡住拖慢整体 ) resp.raise_for_status() # 主动抛出HTTP错误(比如404、500) return { 'url': url, 'status_code': resp.status_code, 'response': resp.json() } except Exception as e: # 捕获所有异常,避免单个请求失败导致整个程序崩溃 return { 'url': url, 'error': str(e) } if __name__ == '__main__': # 创建线程池,max_workers可以根据测试调整(IO密集型任务建议10-30) with ThreadPoolExecutor(max_workers=20) as executor: # 给每个URL提交一个请求任务 futures = [executor.submit(fetch_ethnicity, row[1]) for row in df.itertuples()] # 遍历所有任务的结果并打印 for future in futures: result = future.result() if 'error' in result: print(f"⚠️ URL {result['url']} 请求失败: {result['error']}") else: print(f"✅ URL {result['url']} 状态码: {result['status_code']}") print(f"响应内容: {result['response']}")
关键改动说明:
- 封装请求函数:把原来循环里的请求逻辑抽成
fetch_ethnicity,这样线程池可以调用这个函数处理每个URL。 - 线程池管理:用
ThreadPoolExecutor自动创建和回收线程,不用手动处理线程的生命周期。max_workers设20是个不错的起点,你可以根据实际测试调整——太大可能会被目标服务器限流,太小提速效果不明显。 - 异常处理:添加了try-except块,确保某个请求失败不会影响其他请求,还能清晰看到错误信息。
- URL参数优化:用
params参数代替字符串拼接,自动处理URL编码,避免因为URL里有特殊字符导致请求失败。
进阶优化:复用连接池进一步提速
如果基础版本还不够快,可以复用requests.Session来减少TCP握手的开销——每个线程用自己的session,避免线程安全问题:
import pandas as pd import requests import threading from concurrent.futures import ThreadPoolExecutor auth_token = 'Wy' df = pd.read_csv('/instaurls.csv') # 线程本地存储,每个线程有自己的session thread_local = threading.local() def get_session(): if not hasattr(thread_local, "session"): thread_local.session = requests.Session() # 设置连接池大小,提升连接复用效率 adapter = requests.adapters.HTTPAdapter(pool_connections=10, pool_maxsize=20) thread_local.session.mount('http://', adapter) return thread_local.session def fetch_ethnicity(url): session = get_session() try: resp = session.get( 'http://predict/ethnicity', params={'auth_token': auth_token, 'url': url}, timeout=5 ) resp.raise_for_status() return { 'url': url, 'status_code': resp.status_code, 'response': resp.json() } except Exception as e: return { 'url': url, 'error': str(e) } if __name__ == '__main__': with ThreadPoolExecutor(max_workers=20) as executor: futures = [executor.submit(fetch_ethnicity, row[1]) for row in df.itertuples()] for future in futures: result = future.result() if 'error' in result: print(f"⚠️ URL {result['url']} 请求失败: {result['error']}") else: print(f"✅ URL {result['url']} 状态码: {result['status_code']}") print(f"响应内容: {result['response']}")
这个版本通过复用HTTP连接,能进一步减少请求的延迟,对于大量请求来说效果更明显。
测试建议
- 先跑基础版本,看看耗时有没有降到5秒以内,如果还不够,再调大
max_workers(比如到30)。 - 如果目标服务器有并发限制,别把线程数设得太高,否则可能会收到429(请求过多)错误。
内容的提问来源于stack exchange,提问作者Rehan Aziz
相关产品推荐
相关产品推荐

