不循环排水或丢弃发电机?

8 浏览
0 Comments

不循环排水或丢弃发电机?

在 CSP 风格的进程的异常处理程序中,为了让阻塞中的其他进程能够发送消息并完成,我需要读取并丢弃通道的全部内容。接口提供了用于接收的生成器,有没有比以下方法更快地消耗和丢弃生成器的全部内容的方式?

for _ in chan:
    pass

有没有更快的方式消耗和丢弃生成器的全部内容?

0
0 Comments

问题出现的原因是Python中在没有循环的情况下如何排空或丢弃生成器。解决方法可以尝试使用reduce函数或者使用普通的循环语句。

使用reduce函数的方法如下:

reduce(lambda _, __: None, chan)

但是老实说,我认为使用普通的循环语句效果不会比这个更好。因为"channel"可能涉及到I/O操作,而这个操作本身就是性能瓶颈。

Python中的函数调用开销相对较高。对每个元素调用一个lambda函数比使用普通的循环语句要慢得多。

我在我的答案中添加了一些简单的时间计算。

0
0 Comments

解决方法:使用`collections.deque()`方法来处理生成器,可以更快速地处理。具体的代码如下:

collections.deque(chan, maxlen=0)

原因:根据测试结果来看,使用`collections.deque()`方法相比其他方法更快。具体的测试结果如下:

import collections
a = range(100000)
# 使用reduce方法
%timeit reduce(lambda _, __: None, a)  # 13.5 ms per loop
# 使用for循环
%timeit for dummy in a: pass  # 1.75 ms per loop
# 使用collections.deque()方法
%timeit collections.deque(a, maxlen=0)  # 1.51 ms per loop

此外,还有关于使用下划线`_`作为变量名的讨论。在Python中,使用下划线作为变量名没有特殊的含义,但是它容易与Python交互式环境中的下划线(表示上一个表达式的结果)和常用的`gettext`别名发生冲突。因此,建议使用其他变量名,如`dummy`或`unused`。在其他语言中,下划线可能有特殊的含义,但在Python中没有。虽然在一些情况下,使用下划线作为变量名是常见的,但并没有明确的约定或优势,所以最好避免使用。此外,使用其他更具描述性的变量名可以提高代码的可读性。

另外,还有使用`list(a)`方法来处理生成器的方式,这种方法更加快速,但会在某些情况下占用大量内存。因此,作者没有将该方法包含在测试中。

最后,还提到了`collections.deque()`方法在C语言实现中进行了手动优化,可以更高效地处理生成器。具体的C语言实现代码可以在github.com/python/cpython/blob/…上找到。

0
0 Comments

在这段对话中,问题的出现是因为作者想要了解如何在不使用循环的情况下处理或丢弃一个生成器。解决方法是使用deque数据结构和do_all函数来消耗生成器表达式。

作者开始使用了一个可以重复使用的deque

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循环体中必须防止对其进行任何修改)。大多数情况下,这并不重要,但在作者的情况下,他要绘制非常多的多边形。

作者表示这些测试是基于实际测试的,并提供了一些最基本的测试结果。他还提到了itertools模块,并表示会再次查看Raymond Hettinger关于该模块的讲解。感谢提问者对他的监督。

0