[英]pipeline an iterator to multiple consumers?
是否可以“流水线”跨越多个消费者的发电机消费?
例如,使用以下模式的代码是很常见的:
def consumer1(iterator):
for item in iterator:
foo(item)
def consumer2(iterator):
for item in iterator:
bar(item)
myiter = list(big_generator())
v1 = consumer1(myiter)
v2 = consumer2(myiter)
在这种情况下,多个函数完全消耗相同的迭代器,因此有必要将迭代器缓存在列表中。 由于每个使用者都耗尽了迭代器,因此itertools.tee
毫无用处。
我经常看到这样的代码,我一直希望我可以让消费者一次消费一个项目,而不是缓存整个迭代器。 例如:
consumer1
消费myiter[0]
consumer2
消费myiter[0]
consumer1
消费myiter[1]
consumer2
消费myiter[1]
如果我要编写一个语法,它将看起来像这样:
c1_retval, c2_retval = iforkjoin(big_generator(), (consumer1, consumer2))
您可以使用线程或多处理程序和tee
迭代器进行接近,但是线程消耗的速度不同,这意味着在tee
缓存的双端队列值可能会变得非常大。 这里的目的不是利用并行性或加快任务,而是避免缓存迭代器的大部分。
在我看来,如果不修改使用者,这可能是不可能的,因为控制流在使用者中。 但是,当消费者实际上消费了迭代器时,控件将传递到迭代器的next()
方法中,因此也许可以以某种方式反转控件的流,以便迭代器一次阻止一个消费者,直到可以将其全部供入?
如果可能的话,我不太聪明,怎么做。 有任何想法吗?
这不行吗? 还是您需要整个迭代器,这样才能像这样复制到每个迭代器? 如果是这样,那么我认为您要么必须创建一个副本,要么两次生成列表?
for item in big_generator():
consumer1.handle_item(item)
consumer2.handle_item(item)
由于不更改使用者代码(即在其中包含循环)的局限性,您只剩下两个选择:
itertools.tee
,其缓冲区大小为1,该缓冲区阻止为项目i+1
提供服务,直到将项目i
提供给所有使用者。 没有其他选择。 您无法实现以下所有目的,因为它们是矛盾的:
如果要重复使用,则必须将生成的项目存储在某个位置 。
如果可以更改消费者的代码,那么@monkey的解决方案显然是最简单,最直接的方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.