複数のコンシューマー間でジェネレーターの消費を「パイプライン化」することは可能ですか?
たとえば、次のパターンのコードを使用するのが一般的です。
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]
consumer2
消費するmyiter[0]
consumer1
消費するmyiter[1]
consumer2
消費するmyiter[1]
- 等...
構文を構成するとしたら、次のようになります。
c1_retval, c2_retval = iforkjoin(big_generator(), (consumer1, consumer2))
スレッドまたはマルチプロセッシングとディテレーターに近づくことができますtee
が、スレッドは異なる速度で消費するため、内部にキャッシュされた値の dequetee
が非常に大きくなる可能性があります。ここでのポイントは、並列処理を利用したり、タスクを高速化したりすることではなく、反復子の大きなセクションをキャッシュしないようにすることです。
制御の流れは消費者にあるため、消費者を変更しないとこれは不可能かもしれないと私には思えます。ただし、消費者が実際に反復子コントロールを消費すると、反復子のnext()
メソッドに渡されるため、何らかの形で制御の流れを逆にして、反復子が消費者を一度に 1 つずつブロックして、すべてをフィードできるようにすることは可能でしょうか?
これが可能である場合、私はその方法を理解できるほど頭が良くありません。何か案は?