Requests Session在ThreadPoolExecutor多线程场景下是否支持异步请求?
问题梳理
现有代码
content_getters.py 核心实现
def get_page_content(link: str) -> bytes: headers = {"User-Agent": "Mozilla/5.0 (Macintosh; " "Intel Mac OS X 10_11_6) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/61.0.3163.100 Safari/537.36"} response = requests.get(link, headers=headers) html = response.content.decode("utf-8") if response.status_code != requests.codes.ok: raise ConnectionError("Page", link, "returned status code", response.status_code) return response.content def parse_single_page(link): content = get_page_conent(link) # 其余长逻辑代码
main.py 实现
from concurrent.futures.thread import ThreadPoolExecutor from content_getters import get_page_content, extract_links, parse_single_page if __name__ == "__main__": MAX_THREADS = 30 # 获取链接 html: str = get_page_content( "https://www.d20pfsrd.com/bestiary/bestiary-hub/monsters-by-cr/") \ .decode("utf-8") links = extract_links(html) num_threads = min(MAX_THREADS, len(links)) with ThreadPoolExecutor(max_workers=num_threads) as executor: # 异步执行,线程完成任务后返回结果 results = [result for result in executor.map(parse_single_page, links)]
背景与疑问
requests官方文档说明:
若向同一主机发起多个请求,底层TCP连接会被复用,可带来显著性能提升
当前代码每次调用requests.get()都会创建独立Session,现有两个疑问:
- Session对象本身对所有通过它发起的请求是否是同步(串行)处理的?
- 如果我在
concurrent.futures.thread.ThreadPoolExecutor的所有线程中共用同一个Session对象,而非当前每个线程单独创建Session,是否还能实现异步请求效果?
问题解答
疑问1解答
Session本身不会对请求做串行同步处理。Session的核心作用是复用请求配置、维护会话状态、管理TCP连接池,本身没有调度请求执行顺序的逻辑。你在单线程中通过同一个Session发起多个请求表现为串行,是因为单线程的代码执行逻辑本身就是顺序同步的,和Session无关。
疑问2解答
首先requests的Session 不是线程安全的,多线程直接共用同一个Session实例可能会出现状态数据错乱、请求异常等问题,不推荐这么操作。
如果想要享受TCP连接复用的性能收益,同时保留多线程异步请求的效果,推荐的实现方案是每个线程单独持有一个独立的Session实例:同一个线程内发往同一主机的请求会复用底层TCP连接,不同线程的Session相互隔离不存在线程安全问题,同时多线程的异步执行逻辑完全不受影响,性能远优于当前每次请求新建Session的实现。
内容的提问来源于stack exchange,提问作者qalis
相关产品推荐
相关产品推荐

