python - 如何解决以元组为值的嵌套字典的性能问题?
问题描述
我编写了一个程序,它逐行读取 csv 文件并同时进行分组操作。这运行得相当好,直到数据集达到某个阈值,程序开始随时间线性增加。
用于处理这些文件的代码如下:
import time
data = {}
with open("./[path]/[to]/[file].csv") as f:
start = time.time()
i = 0
f.readline() # Ignore header line
for l in f:
_, client, date, amount, io, ca, cat, mt = l.split(',')
amount = float(amount)
sumDay, sizeDay, meanDay = data.setdefault(client, {}).setdefault(date, (0, 0, 0))
data[client][date] = (sumDay + amount, sizeDay + 1, (meanDay * sizeDay + amount) / (sizeDay + 1))
i += 1
if i % 500000 == 0:
print(time.time() - start)
start = time.time()
csv 文件结构(去掉了一些不必要的信息)如下:
,ClientId,Date,Amount,[...]
0,C5841516,2020-01-01 09:00:00,137.71,[...]
1,C3317977,2020-01-01 09:00:00,136.51,[...]
2,C5107526,2020-01-01 09:00:00,1060.94,[...]
3,C5087842,2020-01-01 09:00:00,130.89,[...]
4,C2938277,2020-01-01 09:00:00,793.64,[...]
5,C9799246,2020-01-01 09:00:00,734.12,[...]
6,C2035898,2020-01-01 09:00:00,107.03,[...]
7,C9310000,2020-01-01 09:00:00,89.17,[...]
8,C4054857,2020-01-01 09:00:00,123.3,[...]
9,C4067165,2020-01-01 09:00:00,846.7,[...]
我已经打印了从数据集中读取最后 500k 行所花费的时间。这些值与 csv 中的客户端计数和行数一起描述如下。
5k clients 3.8m lines | 10.5k clients 16m lines | 11k clients 16.7m lines
0.5572941303253174 | 0.5842881202697754 | 0.7967188358306885
0.5774965286254883 | 0.6746623516082764 | 1.1029884815216064
0.6105935573577881 | 0.6639199256896973 | 1.4002125263214111
0.7133028507232666 | 0.6712498664855957 | 1.883500337600708
0.7059860229492188 | 0.6454544067382812 | 2.0164811611175537
0.6402852535247803 | 0.6314959526062012 | 2.3338706493377686
0.6159951686859131 | 0.6306426525115967 | 2.6350154876708984
0.6128799915313721 | 0.6442699432373047 | 3.265746831893921
0.6154458522796631 | 0.6928198337554932 | 3.409559726715088
0.6257271766662598 | 0.6547060012817383 | 3.964728355407715
0.61846923828125 | 0.6538820266723633 | 4.057897329330444
0.6247692108154297 | 0.6627013683319092 | 4.411986589431763
0.6428296566009521 | 0.655012845993042 | 4.914895296096802
0.6292152404785156 | 0.6570413112640381 | 6.285972833633423
0.6239409446716309 | 0.6641659736633301 | 5.72735857963562
... | ... | goes up to 20s
9.5s total | 20s total | 265s total
数据集大小增加 5%(10.5k 与 11k 客户端)使时间随时间线性增加,而对于较小的数据集,无论大小如何,时间都保持不变。
我发现用列表替换存储 sumDay、sizeDay 和 meanDay 的元组会使代码不会随着时间的推移而增加。但是对于较小的数据集,这表现得更差。(每 50 万行约 0.9 秒,而不是每 50 万行约 0.6 秒)
这里发生了什么?为什么存储在嵌套字典中的元组会使代码在达到某个键阈值后随时间增加?如果不使用列表而不是元组,如何避免这种情况,因为这会影响 50% 的性能?
解决方案
这是 GC https://bugs.python.org/issue2607#msg65341 非常古老但可悲的是真的
推荐阅读
- c - 围绕变量“”的堆栈已损坏 - C
- visual-studio - 在 Visual Studio 2019 中启动 Docker-compose 时无法启动调试适配器?
- c# - AutoMapper:DTO 和实体之间的映射
- dictionary - PyQt5 QTreeWidget 索引(col)不引用递归 QTree 中的 Root Parent
- javascript - 来自 AsyncStorage 更改的 React Native 触发器 useEffect
- linux - 如何有效地将大页面支持的缓冲区传递给 Linux 中的 BM DMA 设备?
- javascript - 有没有办法在 sapui5 中制作受保护的路线
- php - 带有子查询和 foreach 的 Laravel 查询
- python - 在cvxpy中连接目标函数
- html - 如何更改表格css中仅一行的样式