使用迭代器的最快(最Pythonic)的方式

2024-01-30

我很好奇使用迭代器最快的方法是什么,也是最 Pythonic 的方法。

例如,假设我想创建一个迭代器map内置函数会累积一些东西作为副作用。我实际上并不关心结果map,只是副作用,所以我想以尽可能少的开销或样板来完成迭代。就像是:

my_set = set()
my_map = map(lambda x, y: my_set.add((x, y)), my_x, my_y)

在这个例子中,我只是想通过迭代器来积累东西my_set, and my_set在我真正跑完之前只是一个空集my_map。就像是:

for _ in my_map:
    pass

或裸体

[_ for _ in my_map]

有效,但它们都感觉笨重。有没有一种更 Pythonic 的方法来确保迭代器快速迭代,以便您可以从一些副作用中受益?


基准

我对上述两种方法进行了测试,结果如下:

my_x = np.random.randint(100, size=int(1e6))
my_y = np.random.randint(100, size=int(1e6))

with my_set and my_map如上所定义。我用 timeit 得到了以下结果:

for _ in my_map:
    pass
468 ms ± 20.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

[_ for _ in my_map]
476 ms ± 12.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

两者之间没有真正的区别,而且都感觉笨重。

注意,我得到了类似的性能list(my_map),这是评论中的建议。


虽然您不应该仅仅为了副作用而创建映射对象,但实际上有一个在itertools docs https://docs.python.org/3/library/itertools.html#itertools-recipes:

def consume(iterator, n=None):
    "Advance the iterator n-steps ahead. If n is None, consume entirely."
    # Use functions that consume iterators at C speed.
    if n is None:
        # feed the entire iterator into a zero-length deque
        collections.deque(iterator, maxlen=0)
    else:
        # advance to the empty slice starting at position n
        next(islice(iterator, n, n), None)

对于“完全消耗”的情况,可以简化为

def consume(iterator):
    collections.deque(iterator, maxlen=0)

Using collections.deque这种方式可以避免存储所有元素(因为maxlen=0)并以 C 速度迭代,没有字节码解释开销。甚至还有一个专用快速通道 https://github.com/python/cpython/blob/v3.6.5/Modules/_collectionsmodule.c#L356在双端队列实现中使用maxlen=0deque 来消耗迭代器。

Timing:

In [1]: import collections

In [2]: x = range(1000)

In [3]: %%timeit
   ...: i = iter(x)
   ...: for _ in i:
   ...:     pass
   ...: 
16.5 µs ± 829 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [4]: %%timeit
   ...: i = iter(x)
   ...: collections.deque(i, maxlen=0)
   ...: 
12 µs ± 566 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

当然,这都是基于CPython的。解释器开销的整体性质与其他 Python 实现非常不同,并且maxlen=0快速路径特定于 CPython。看阿巴纳特的回答 https://stackoverflow.com/a/50938287/对于其他 Python 实现。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用迭代器的最快(最Pythonic)的方式 的相关文章