如何用ThreadPoolExecutor指定单线程执行get_cookie避免JIRA重复登录?
解决方案
问题核心
原代码里的cookie和cookie_time是全局变量,线程间没有同步机制,导致多个线程能同时通过过期判断,进而重复执行get_cookie(),触发多次登录操作。
方案1:用线程锁保护cookie更新逻辑
这是最直接的修复方式,通过threading.Lock把cookie检查和更新的逻辑变成原子操作,确保同一时间只有一个线程能执行刷新动作,其他线程会等待锁释放后再检查,此时cookie已经更新完成,不会重复刷新。
修改后的代码示例:
import concurrent.futures as fs import time import threading # 初始化锁、cookie和时间 cookie_lock = threading.Lock() cookie = get_cookie() cookie_time = time.time() page_size = 1000 total_num_issues = 100000 def safe_refresh_cookie(): global cookie, cookie_time # 二次检查,防止等待锁的线程重复刷新 if time.time() - cookie_time > 300: cookie = get_cookie() cookie_time = time.time() with fs.ThreadPoolExecutor(max_workers=30) as ex: future_list = [] for start_at in range(0, total_num_issues + 1, page_size): # 加锁执行cookie检查和刷新 with cookie_lock: safe_refresh_cookie() extra_params = {"startAt": start_at, "maxResults": page_size} future_list.append(ex.submit(send_request, url, session, {**extra_params})) for future in fs.as_completed(future_list): issues += future.result()["issues"]
方案2:指定单个线程专门负责cookie刷新
可以启动一个后台线程,定时检查cookie有效期并提前自动刷新,业务线程完全不用处理cookie的问题,直接使用全局的有效cookie即可。
代码示例:
import concurrent.futures as fs import time import threading import atexit cookie = get_cookie() cookie_time = time.time() stop_refresh = threading.Event() def cookie_refresher(): global cookie, cookie_time while not stop_refresh.is_set(): # 提前10秒刷新,避免刚好过期时业务线程出错 time_until_expire = 300 - (time.time() - cookie_time) if time_until_expire <= 10: cookie = get_cookie() cookie_time = time.time() # 每隔10秒检查一次 time.sleep(10) # 启动后台刷新线程(设为守护线程,主程序退出时自动终止) refresh_thread = threading.Thread(target=cookie_refresher, daemon=True) refresh_thread.start() # 程序退出时主动停止刷新线程,避免资源泄漏 atexit.register(lambda: stop_refresh.set()) page_size = 1000 total_num_issues = 100000 with fs.ThreadPoolExecutor(max_workers=30) as ex: future_list = [] for start_at in range(0, total_num_issues + 1, page_size): extra_params = {"startAt": start_at, "maxResults": page_size} future_list.append(ex.submit(send_request, url, session, {**extra_params})) for future in fs.as_completed(future_list): issues += future.result()["issues"]
注意事项
- 方案1的锁会带来轻微性能开销,但对于JIRA请求这类IO密集型任务,影响几乎可以忽略。
- 方案2要确保后台线程能被正确终止,避免程序退出后残留线程。
- 无论用哪种方案,要保证
send_request函数使用的是最新的全局cookie,如果是通过参数传递,需确保提交任务时传入的是当前最新值。
内容的提问来源于stack exchange,提问作者Saguro
相关产品推荐
相关产品推荐

