【问题标题】:Drain or discard a generator without looping?在不循环的情况下排空或丢弃生成器?
【发布时间】:2012-03-11 09:41:35
【问题描述】:

在 CSP 样式进程的异常处理程序中,我需要读取并丢弃通道的全部内容,以允许其他阻塞的进程向它发送数据。接口呈现一个生成器用于接收,有没有比下面的更快的方式来消耗和丢弃一个生成器的全部内容?

for _ in chan:
    pass

【问题讨论】:

标签: python python-3.x generator


【解决方案1】:

有一种方法稍微快一点:

collections.deque(chan, maxlen=0)

不过,您的代码使意图更加清晰,因此您应该衡量是否存在明显差异。我几乎总是更喜欢你的代码。

(不过,我永远不会使用 _ 作为变量名。它往往会让人感到困惑,与交互式 shell 中的 _ 以及常见的 gettext 别名发生冲突。)

编辑:以下是一些简单的时间安排:

In [1]: import collections

In [2]: a = range(100000)

In [3]: timeit reduce(lambda _, __: None, a)
100 loops, best of 3: 13.5 ms per loop

In [4]: timeit for dummy in a: pass
1000 loops, best of 3: 1.75 ms per loop

In [5]: timeit collections.deque(a, maxlen=0)
1000 loops, best of 3: 1.51 ms per loop

【讨论】:

  • _ 是一次性变量的通用名称,我想。
  • @DavidZaslavsky:在某些语言中它具有特殊含义(例如 Go)。它在 SO 上变得很丰富,即使对于 Python 也是如此,但在 Python 中使用它是一个坏主意。使用这样的名称没有任何好处。称它为dummy,您将避免任何混淆。
  • @DavidZaslavsky:在 Python 中使用它没有严格的约定。据我所知,python.org 上根本没有提到它。我已经被问了几十次这种奇怪的语法是什么意思。显然,没有人问过我为什么将未使用的变量称为 dummyunused
  • @DavidZaslavsky:这当然很常见。一些实例甚至出现在 Python 的标准库中。但是“它很常见”和“这是一个约定”之间是有区别的。 “它很常见”和“这是个好主意”之间肯定有区别。
  • @LennartRegebro:使用list(a) 而不是[x for x in a] 会快得多。我将list(a) 与上述选项一起计时(它非常快!),但我没有包括计时,因为它创建了一个包含所有结果的不需要的列表,在某些情况下可能需要大量内存。我只包含了立即将所有内容发送到 Orcus 的解决方案。
【解决方案2】:

我已经开始使用可以在需要时重复使用的双端队列:

do_all = deque(maxlen=0).extend

然后我可以使用生成器表达式:

do_all(poly.draw() for poly in model.polys)

【讨论】:

  • 但这并不比for poly in model.polys: poly.draw()快,也不是更易读。你为什么用它? (使用你已经拥有的一些可迭代对象可能会稍微快一些,但是显式构造一个生成器只是为了以这种方式使用它对我来说似乎毫无意义。)
  • 您的评论是基于实际测试还是直觉?我已经对此进行了一些测试,我得到了大约 5% 的改进,因为 do_all 在 C 中进行迭代,而不是迭代 Python 变量poly(必须防止对 for 循环体进行任何修改) .大多数for循环都没关系,但就我而言,我正在绘制许多,许多多边形。 (在fractallography.com查看我的作品)
  • 这是基于实际测试的,其中很多是我很久以前做过的。我刚刚又做了最基本的,见gist.github.com/1877613
  • "do_all 在 C 中进行迭代" - 如果您传入生成器表达式,则不会。生成器表达式为应该在每次迭代中执行的部分创建一个 Python 代码对象。
  • 我得再回去看看 itertools 模块,看看 Raymond Hettinger 到底在说什么!谢谢你让我诚实!
【解决方案3】:

你可以试试:

reduce(lambda _, __: None, chan)

但老实说,我认为你不会比普通循环做得更好。 “通道”表明 I/O 无论如何都会成为瓶颈。

【讨论】:

  • Python 有相当高的函数调用开销。为每个元素调用lambda 函数比纯 for 循环慢得多。
  • 我在回答中添加了一些简单的时间安排。
猜你喜欢
  • 1970-01-01
  • 2020-03-03
  • 2017-09-05
  • 1970-01-01
  • 1970-01-01
  • 2022-11-10
  • 1970-01-01
  • 1970-01-01
  • 2018-10-26
相关资源
最近更新 更多