如何在Python多线程间共享可更新的saved_session以复用代理会话?
问题分析与解决方案
你的问题主要源于两个核心问题:普通字典的线程不安全特性,以及线程创建方式错误。以下是具体的修复方案:
1. 核心问题说明
- 普通Python字典不是线程安全的,多线程同时读写时会出现数据竞争,导致写入的会话数据无法被其他线程读取到。
- 你在创建线程时,错误地将
target设置为函数调用(from_page(url,)),这会直接在主线程执行函数,而非启动子线程运行,导致多线程逻辑完全失效。
2. 完整修复代码
导入线程锁并初始化全局资源
from threading import Thread, Lock import test_by_me # 保存会话的字典 saved_session: dict = {} # 线程锁,用于同步对saved_session的读写操作 session_lock = Lock()
修改注入函数,加锁写入会话数据
def injection(session, response): if test_by_me.challenge(session, response): solve = test_by_me.solve(session, response) # 加锁保证写入操作的原子性,避免多线程冲突 with session_lock: # 复制headers和cookies,避免后续修改session影响已保存的会话 saved_headers = session.headers.copy() saved_cookies = session.cookies.copy() saved_session[session.proxies["https"]] = { "headers": saved_headers, "cookies": saved_cookies } return solve else: return response def create_session(): return test_by_me.create_scraper( Hook=injection, )
修改线程执行函数,加锁读取会话数据
def from_page(url): while True: with create_session() as session: proxy = proxies.random_proxies() session.proxies = {'https': proxy} # 加锁读取最新的会话数据 with session_lock: proxy_session = saved_session.get(proxy) if proxy_session: # 使用update方法合并headers,避免覆盖session默认配置 session.headers.update(proxy_session['headers']) # 恢复保存的cookies session.cookies.update(proxy_session['cookies']) resp = session.get(url, timeout=6) # 后续业务逻辑处理 ...
修正主线程的线程创建方式
def main() -> None: db_urls = [...] # 正确创建线程:target为函数对象,args传递参数元组 for url in db_urls: Thread(target=from_page, args=(url,)).start() if __name__ == '__main__': main()
3. 关键修复点解释
- 线程锁(Lock):通过
with session_lock上下文管理器,确保同一时间只有一个线程能读写saved_session,彻底避免数据竞争问题。 - 会话数据复制:对
headers和cookies进行复制操作,防止后续修改当前session时,意外污染已保存的会话数据。 - 线程创建修正:将
target设置为函数本身,通过args传递参数,确保函数在子线程中执行,而非主线程直接调用。
4. 额外优化建议
- 可以给保存的会话添加过期时间,定期清理失效的代理会话,避免内存占用过高。
- 如果代理数量极大或读写操作频繁,可以考虑使用
concurrent.futures.ThreadPoolExecutor简化线程管理,同时保持锁机制不变。
内容的提问来源于stack exchange,提问作者PythonNewbie
相关产品推荐
相关产品推荐

