Python—向持久主目录添加多个列表目录时的性能
我有一个字典“更新”算法,我怀疑这不是最有效的方法。当我运行程序并不断向现有词典添加新词典时,性能会随着时间的推移显著降低。我想找到一种更有效的方法 我的字典更新操作 我有一个循环,每次迭代都会处理一个文件,并生成一个“dict of list of dict”。每个主dict键都有一个列表值,其项本身就是dict,其中可以有多个。在本例中,属于B的列表中有两个dict。我可能会处理第一个文件并得到以下结果:Python—向持久主目录添加多个列表目录时的性能,python,list,performance,dictionary,Python,List,Performance,Dictionary,我有一个字典“更新”算法,我怀疑这不是最有效的方法。当我运行程序并不断向现有词典添加新词典时,性能会随着时间的推移显著降低。我想找到一种更有效的方法 我的字典更新操作 我有一个循环,每次迭代都会处理一个文件,并生成一个“dict of list of dict”。每个主dict键都有一个列表值,其项本身就是dict,其中可以有多个。在本例中,属于B的列表中有两个dict。我可能会处理第一个文件并得到以下结果: {'A': [{'filename': 6311, 'id': 6634, 'num_
{'A': [{'filename': 6311, 'id': 6634, 'num_transactions': 4969, 'total': 7808}],
'B': [{'filename': 6311, 'id': 3578, 'type': 8268, 'diameter': 2281, 'width': 4617},
{'filename': 6311, 'id': 2289, 'type': 1553, 'diameter': 4104, 'width': 8725}]}
然后我可能会处理另一个文件并得到以下结果:
{'C': [{'filename': 7775, 'id': 177, 'count': 6139, 'needed': 7905}],
'B': [{'filename': 7775, 'id': 7540, 'type': 9854, 'diameter': 3729, 'width': 9145},
{'filename': 7775, 'id': 27, 'type': 2380, 'diameter': 7209, 'width': 6023}]}
然后,我将这些dict组合成一个主dict,在主dict中,我根据它们的键值不断地组合列表。上述两个DICT的组合将导致(此处的顺序是任意的,但为可读性排序):
请注意,我必须有一个最终的主目录,其中包含我所有字典中的合并数据,这是不可协商的
算法与性能
下面是一个完整的程序,用于生成随机的cur_dict
,并将其结果连续添加到master_dict
。函数add_to_master_dict()
表示我的更新算法
import random
import timeit
import matplotlib.pyplot as plt
random.seed(0)
a_keys = ['id', 'num_transactions', 'total']
b_keys = ['id', 'type', 'diameter', 'width']
c_keys = ['id', 'count', 'needed']
key_dict = {'A':a_keys, 'B':b_keys, 'C':c_keys}
def generate_cur_dict(key_dict):
cur_dict = {}
filename_int = random.randint(0, 10000)
for main in random.sample(key_dict.keys(),
random.randint(1, len(key_dict.keys()))):
cur_dict[main] = []
num_rows = random.choice([1, 1, random.randint(1, 3)])
for _ in range(num_rows):
temp_dict = {}
temp_dict['filename'] = filename_int
for k in key_dict[main]:
temp_dict[k] = random.randint(0, 10000)
cur_dict[main].append(temp_dict)
return cur_dict
# Hacky use of variable scope by assuming existence of cur/master_dict,
# but easiest way to pass to timeit
def add_to_master_dict():
if not master_dict: # master_dict is empty
master_dict.update(cur_dict)
else:
for k in cur_dict.keys():
if k in master_dict:
# In case of None value rather than a list
if cur_dict[k] is None:
continue
else:
# Combine the two lists based on key
master_dict[k] = master_dict[k] + cur_dict[k]
else:
# If key not in master dict, just add the cur_dict value to the
# master_dict
master_dict[k] = cur_dict[k]
master_dict = {}
times = []
for i in range(50001):
cur_dict = generate_cur_dict(key_dict)
times.append(timeit.timeit(add_to_master_dict, number=1))
# Easy visual way to see how much it slows down over time
if i % 1000 == 0:
print(i)
plt.figure(figsize=(10, 6))
plt.plot(times)
我知道这不是使用timeit的最优雅的方式——我没有计算执行的平均值,所以有很多变化——但我只是想演示一下这个概念。应该清楚的是,如果您在大量的迭代中运行此操作,add_to_master_dict()
会陷入相当大的困境,因此我可能会在这里看到我的更新呈指数增长
对于如何以(希望)达到线性时间的方式执行更新操作,有什么建议吗?我已经能够找到在简单情况下运行良好的dict/list更新算法,但在我的dict/list用例中却没有
master_dict[k] = master_dict[k] + cur_dict[k]
每次执行时创建一个新列表。扩大现有清单
master_dict[k] += cur_dict[k]
要快得多。在我的机器上,执行时间从1分钟46.857秒变为8.027秒
我不是专家,但我怀疑这两个版本的代码都在大致的线性时间内运行。然而,在原始代码中,必须为行的每次执行构造长度为n+k的新列表,而在改进版本中,现有列表由k个元素扩展,这需要更少的内存分配和对象构造
*扩展一个列表是在摊销的线性时间内运行的-看啊,我太复杂了-当我处理一个“dict of list of dict”时,它最终仍然只是在现有列表中添加一个列表,答案很清楚。同时也感谢对big-O执行的澄清。
master_dict[k] += cur_dict[k]