2013-03-24 7 views
7

Czy możliwe jest "potokowe" zużycie generatora przez wielu klientów?Potokować iterator dla wielu klientów?

Na przykład często można mieć kod z tego wzoru:

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) 

W tym przypadku, wiele funkcji całkowicie zużywa taką samą iterator, co powoduje konieczność buforowania iterator na liście. Ponieważ każdy użytkownik zużywa iterator, itertools.tee jest bezużyteczny.

Często widzę taki kod i zawsze chciałbym, aby konsumenci mogli konsumować po jednym elemencie, zamiast cachowania całego iteratora. Np .:

  1. consumer1 zużywa myiter[0]
  2. consumer2 zużywa myiter[0]
  3. consumer1 zużywa myiter[1]
  4. consumer2 zużywa myiter[1]
  5. etc ...

Gdybym MA ke się składni, to będzie wyglądać następująco:

c1_retval, c2_retval = iforkjoin(big_generator(), (consumer1, consumer2)) 

można zbliżyć się z nici lub multiprzetwarzania i tee d iteratory, ale nici spożywać przy różnych prędkościach, co oznacza, że ​​wartość deque buforowane wewnątrz tee może dostać bardzo duże. Nie chodzi tutaj o wykorzystanie równoległości lub przyspieszanie zadań, ale unikanie buforowania dużych sekcji iteratora.

Wydaje mi się, że może to być niemożliwe bez modyfikacji konsumentów, ponieważ kontrola przepływu odbywa się w konsumentach. Jednakże, gdy konsument faktycznie zużywa kontrolę iteracyjną, przechodzi do iteracyjnej metody next(), więc być może jest możliwe odwrócenie przepływu kontroli w jakiś sposób, tak aby iterator blokował konsumentów po kolei, dopóki nie będzie mógł ich wszystkich podać?

Jeśli to możliwe, nie jestem wystarczająco sprytny, aby zobaczyć, jak. Jakieś pomysły?

+0

Jeśli punkt niekoniecznie jest równoległy, istnieje możliwość scentralizowania iteratora i wysłania danych do każdego * konsumenta *, może przy użyciu klasy z listą 'position% task', która zwraca wartości dla każdego' wydajność ". – Rubens

+0

Może to zrobić za pomocą coroutines? Jeśli masz centralny iterator, który wysyła elementy do pojedynczych użytkowników, możliwe jest uzyskanie tego, co chcesz. W każdym razie myślę, że powinieneś sprawdzić, czy oszczędności pamięci są tak ważne, ponieważ sprawy będą się komplikować. Osobiście po prostu pójdę z 'myiter = list (the_generator())' i przejdę dookoła sekwencji. – Bakuriu

Odpowiedz

1

z ograniczeniem nie zmienia kod konsumentów (tj mający pętlę w nich), jesteś już tylko dwie opcje:

  1. podejścia, które już zawierają w swoim pytaniu: buforowanie wygenerowane elementy w pamięci, a następnie wielokrotne powtarzanie ich.
  2. uruchamianie każdego konsumenta w wątku i wdrożenie pewnego rodzaju zsynchronizowanego - itertools.tee, z buforem o rozmiarze = 1, który blokuje wyświetlanie elementu i+1, dopóki element i nie został dostarczony do wszystkich klientów.

Nie ma innych opcji.Nie można osiągnąć wszystkie poniżej, są one sprzeczne:

  1. obejmujący generator
  2. z pętlą do konsumpcji to wszystko
  3. następnie (serially-) po poprzedniego pętli zakończeniu, po inny układ do konsumpcji to wszystko jeszcze
  4. tylko utrzymanie o (1) elementów pamięci (lub dysków, etc.), podczas spożywania ich
  5. nie regeneracji (nie ponownego tworzenia Generator)

Wygenerowane elementy muszą być przechowywane gdzieś, jeśli chcesz je ponownie wykorzystać.

Jeśli zmiana kodów konsumentów jest akceptowalna, to oczywiste jest, że rozwiązanie @ monkey jest najprostsze i najprostsze.

1

Czy to nie działa? Czy potrzebujesz całego iteratora, więc kopia dla każdego takiego, nie zadziała? Jeśli tak, to czy musisz utworzyć kopię, czy wygenerować ją dwukrotnie?

for item in big_generator(): 
    consumer1.handle_item(item) 
    consumer2.handle_item(item) 
+2

Wymaga to przepisywania konsumentów. Wielu konsumentów akceptuje sekwencję i sama ją konsumuje. Ten schemat działa poprzez odwrócenie kontroli, więc konsument jest informowany, kiedy go konsumować. (Punktem zwrotów wydajności jest ułatwienie kodowania za pomocą generatorów w tym stylu.) Więc tak naprawdę nie jest to odpowiedź, której szukam. –

Powiązane problemy