最近,我在 Jon Clements 的帮助下发现了 this thread 以下代码的执行时间非常不同。
你知道为什么会这样吗?
评论:self.stream_data 是一个包含许多零和 int16 值的向量元组,create_ZS_data 方法正在执行所谓的 ZeroSuppression。
环境
输入:许多 (3.5k) 个小文件(每个约 120kb)
操作系统:Linux64
Python 版本 2.6.8
基于生成器的解决方案:
def create_ZS_data(self):
self.ZS_data = ( [column, row, self.stream_data[column + row * self.rows ]]
for row, column in itertools.product(xrange(self.rows), xrange(self.columns))
if self.stream_data[column + row * self.rows ] )
分析器信息:
ncalls tottime percall cumtime percall filename:lineno(function)
3257 1.117 0.000 71.598 0.022 decode_from_merlin.py:302(create_ZS_file)
463419 67.705 0.000 67.705 0.000 decode_from_merlin.py:86(<genexpr>)
乔恩的解决方案:
create_ZS_data(self):
self.ZS_data = list()
for rowno, cols in enumerate(self.stream_data[i:i+self.columns] for i in xrange(0, len(self.stream_data), self.columns)):
for colno, col in enumerate(cols):
# col == value, (rowno, colno) = index
if col:
self.ZS_data.append([colno, rowno, col])
分析器信息:
ncalls tottime percall cumtime percall filename:lineno(function)
3257 18.616 0.006 19.919 0.006 decode_from_merlin.py:83(create_ZS_data)
最佳答案
我看了之前的讨论;您似乎对您的聪明理解在循环方面不如在源代码字符方面有效而感到困扰。当时我没有指出的是,这将是我更喜欢阅读的实现:
def sparse_table_elements(cells, columns, rows):
ncells = len(cells)
non_zeros = list()
for nrow in range(0, ncells, columns):
row = cells[nrow:nrow+columns]
for ncol, cell in enumerate(row):
if cell:
non_zeros.append([ncol, nrow, cell])
return non_zeros
我没有测试过,但我能理解它。有几件事让我觉得可能效率低下。重新计算两个常量单调“无聊”索引的笛卡尔积一定很昂贵:
itertools.product(xrange(self.rows), xrange(self.columns))
然后您使用结果 [(0, 0), (0, 1), ...]
从您的源中执行单个元素索引:
stream_data[column + row * self.rows]
这也比像“Jon 的”实现那样处理更大的切片成本更高。
生成器并不是保证效率的秘方。在这种特殊情况下,已经将 135kb 的数据读入核心,构造不当的生成器似乎确实会让您付出代价。如果你想要简洁的矩阵运算,使用APL ;如果您想要可读的代码,请不要在 Python 中追求疯狂的最小化。
关于python - 为什么遍历枚举比生成器快得多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11611412/