Asyncio队列添加字典元素出现循环覆盖重复问题求助
问题分析:异步分页API请求器队列元素被覆盖的原因
问题描述
实现了带有超时、队列和多工作进程的异步分页API请求器,设置3个工作进程消费队列元素。当请求结果为第1页且总页数大于1时,尝试修改已用参数的page值(从2到总页数)后放入队列:
if result['page'] < result['total_pages'] and result['page'] == 1: for page in range(2, result['total_pages']+1): request_kwargs['params']['page'] = page queue.put_nowait(request_kwargs)
但出现异常:每次循环都会覆盖队列中之前的元素,最终队列里全是最后一次循环设置的page值(比如第6次循环后,6个元素的page都是6)。而直接将page值放入队列时则正常:
if result['page'] < result['total_pages'] and result['page'] == 1: for page in range(2, result['total_pages']+1): queue.put_nowait(page)
问题根源
Python中字典是可变对象,你每次放入队列的request_kwargs都是同一个字典的引用,而非新的独立字典。队列里存储的只是指向这个字典的内存地址,后续循环中修改request_kwargs['params']['page']时,所有指向该字典的引用都会看到这个变化,导致之前放入队列的元素也被同步修改。
而直接放page值正常,是因为整数是不可变对象,每次放入队列的都是全新的整数实例,后续循环不会影响之前的元素。
解决方案
每次循环时创建request_kwargs的独立副本,再修改page值后放入队列。常用两种方式:
1. 深拷贝(适合复杂嵌套结构)
使用copy.deepcopy创建完全独立的字典副本:
import copy if result['page'] < result['total_pages'] and result['page'] == 1: for page in range(2, result['total_pages']+1): new_request_kwargs = copy.deepcopy(request_kwargs) new_request_kwargs['params']['page'] = page queue.put_nowait(new_request_kwargs)
2. 手动浅拷贝(适合简单结构)
如果request_kwargs的结构不复杂,也可以逐层复制:
if result['page'] < result['total_pages'] and result['page'] == 1: for page in range(2, result['total_pages']+1): # 复制params字典 new_params = request_kwargs['params'].copy() new_params['page'] = page # 构建新的请求参数字典 new_request_kwargs = { 'method': request_kwargs['method'], 'url': request_kwargs['url'], 'params': new_params } queue.put_nowait(new_request_kwargs)
内容的提问来源于stack exchange,提问作者Fosly
相关产品推荐
相关产品推荐

