Drain or discard a generator without looping?

2020-03-25 09:25发布

In an exception handler for a CSP style process, I need to read and discard the entire contents of a channel in order to allow other processes that are blocking to send to it to complete. The interface presents a generator for receiving, is there a faster way to consume and discard the entire contents of a generator than the following?

for _ in chan:
    pass

3条回答
兄弟一词,经得起流年.
2楼-- · 2020-03-25 10:00

I've started using a deque that I can reuse if need be:

do_all = deque(maxlen=0).extend

Then I can consume generator expressions using:

do_all(poly.draw() for poly in model.polys)
查看更多
我命由我不由天
3楼-- · 2020-03-25 10:12

You might try:

reduce(lambda _, __: None, chan)

But honestly I don't think you're going to do much better than the plain loop. "channel" suggests I/O which is going to be the bottleneck anyway.

查看更多
趁早两清
4楼-- · 2020-03-25 10:15

There is a way that is slightly faster:

collections.deque(chan, maxlen=0)

Your code makes the intention much clearer, though, so you should measure if there is a discernible difference. I'd almost always prefer your code.

(I'd never use _ as a variable name, though. It tends to confuse people, clashes with _ in the interactive shell and with the common gettext alias.)

Edit: Here are some simple timings:

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
查看更多
登录 后发表回答