[英]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.