如果我按行或按列遍历2D矩阵,是否有任何性能差异。
例如:
import random
import time
l = []
for i in range(1000000):
temp = [random.random() for x in range(10)]
l.append(temp)
start_time = time.time()
for i in range(1000000):
for j in range(10):
l[i][j] -= 0
end_time = time.time()
time_taken_row_wise = end_time - start_time
start_time = time.time()
for i in range(10):
for j in range(1000000):
l[j][i] -= 0
end_time = time.time()
time_taken_column_wise = end_time - start_time
print(f"ROW WISE: {time_taken_row_wise}")
print(f"COLUMN WISE: {time_taken_column_wise}")
在上面的代码中,为什么按列迭代所需的时间比按行迭代所用的时间要长?
我运行了两次,得到了以下结果:
第一次运行:
ROW WISE: 3.497559070587158
COLUMN WISE: 4.971074819564819
第二次运行:
ROW WISE: 3.638113021850586
COLUMN WISE: 4.855097055435181
发布于 2019-06-10 20:04:41
我得到的结果相距更远:
行数: 11.901052713394165
按列排列: 38.32502007484436
我怀疑这与行/列在内存中的布局以及缓存预取有关(“按行”按照缓存预取机制的预期工作,“按列”在内存页之间来回跳转)。
我将尝试使用perf
来尝试更深入地了解……
编辑: OK,我认为这证实了这一点:
按行的
行数: 11.151209354400635
'python3 by_row.py‘的性能计数器统计信息: 1,130,850,390个缓存-未命中1,102,567,550 L1-dcache-加载-未命中66,438,701 LLC-加载-未命中
按列列出的
列: 39.6846444606781
'python3 by_column.py n.py‘的性能计数器统计信息: 2,842,000,454缓存-未命中1,544,974,094 L1-dcache-加载-未命中305,823,025 LLC-加载未命中
我们看到cache-misses
(必须实际进入内存的内存读取数量)显著增加(比x2更多),这可以解释为什么按列需要更多时间。
L1-dcache和LLC可以为我们提供更多关于缓存成功服务的读取的信息(因此,不计入缓存未命中),但仍然可能导致差异,基于使用的缓存(越接近L1越好)
发布于 2019-06-10 20:10:23
对我来说,也是一样的。
ROW WISE: 2.68672251701355
COLUMN WISE: 2.7386820316314697
你的意思是为什么它不完全一样?enthropy?
代码:
import random
import time
l = []
for i in range(1000000):
temp = [random.random() for x in range(10)]
l.append(temp)
start_time = time.time()
for i in range(1000000):
for j in range(10):
l[i][j] -= 0
end_time = time.time()
time_taken_row_wise = end_time - start_time
start_time = time.time()
for i in range(10):
for j in range(1000000):
l[j][i] -= 0
end_time = time.time()
time_taken_column_wise = end_time - start_time
print("ROW WISE: %s" % time_taken_row_wise)
print("COLUMN WISE: %s" % time_taken_column_wise)
发布于 2020-10-05 12:51:23
正如Adam.Er8所说,性能差异是由于矩阵存储在内存中的方式造成的。根据语言标准的不同,矩阵既可以按行、按列存储,也可以不指定(取决于编译器实现)。
矩阵的
11, 12, 13
21, 22, 23
行式存储将为[11, 12, 13, 21, 22, 23]
按列存储的存储应为[11, 21, 12, 22, 13, 23]
根据您访问索引的方式,您可以进行顺序访问或随机访问。顺序访问在连续的存储器位置中访问矩阵,而随机访问从一个位置跳到另一个位置。因此,当矩阵变得足够大时,随机访问具有高高速缓存未命中频率和高页面故障频率。
了解一种语言(和编译器)如何访问矩阵对软件性能至关重要。简单地改变访问索引的方式可能会有高达14倍的差异!(编译器: g++ o3,矩阵大小为500,有2个索引)
https://stackoverflow.com/questions/56525661
复制相似问题