簡體   English   中英

將迭代器傳遞給多個使用者?

[英]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毫無用處。

我經常看到這樣的代碼,我一直希望我可以讓消費者一次消費一個項目,而不是緩存整個迭代器。 例如:

  1. consumer1消費myiter[0]
  2. consumer2消費myiter[0]
  3. consumer1消費myiter[1]
  4. consumer2消費myiter[1]
  5. 等等...

如果我要編寫一個語法,它將看起來像這樣:

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)

由於不更改使用者代碼(即在其中包含循環)的局限性,您只剩下兩個選擇:

  1. 您已經在問題中包含的方法:將生成的項目緩存在內存中,然后對其進行多次迭代。
  2. 在線程中運行每個使用者,並實現某種itertools.tee ,其緩沖區大小為1,該緩沖區阻止為項目i+1提供服務,直到將項目i提供給所有使用者。

沒有其他選擇。 您無法實現以下所有目的,因為它們是矛盾的:

  1. 有發電機
  2. 有一個循環來消耗所有
  3. 然后, 上一個循環完成之后 (串行),讓另一個循環再次使用所有循環
  4. 在使用它們時僅將O(1)個項目保留在內存(或磁盤等)中
  5. 不重新生成(即不重新創建生成器)

如果要重復使用,則必須將生成的項目存儲在某個位置

如果可以更改消費者的代碼,那么@monkey的解決方案顯然是最簡單,最直接的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM