2012-12-05 13 views
5

Mam bardzo ciężko zrozumieć pracę leniwości i jak działa pamięć podręczna.Krok po kroku przykład lazy-seq

Myślę, że krok po kroku przykład lazy-seq w pracy może naprawdę pomóc tutaj. Na przykład czytałem następujące pytanie:

Clojure lazy sequence usage

ale wciąż nie jest jasne.

Moje pytanie brzmi: w jaki sposób wywołanie określa, czy inne połączenie jest "równe" z połączeniem buforowanym i jak długo pozostaje ono w pamięci podręcznej? Próbowałem (źródło lazy-seq), ale najwyraźniej jest to w Jawie, więc nie mam szczęścia.

Dla prostego leniwego seqa, biorąc tylko jeden argument (jak na przykład lista potęg dwóch), co jeśli zadzwonię to za pomocą 5, a następnie 8? Czy te dwie wartości są buforowane?

Jaki jest sens tworzenia i buforowania nieskończonej listy, aby uzyskać nieskończoną strukturę, jeśli mam zamiar zniszczyć pamięć poprzez buforowanie każdego wejścia, które już nazywałem funkcją leniwą?

Ponieważ mówi, że buforuje wynik przy kolejnych połączeniach ... Z literą "s".

1: wynik dla argumentu jako '1' pamięci podręcznej 2: wynik dla argumentu będącego '2' buforowane 3: doprowadzić do argumentem jest '3' z pamięci podręcznej ... 2 30: zaliczane do 2 30 i to jest wspaniałe, ponieważ jestem leniwy i wszystko, ale teraz jest 2 ** 30 pamięci podręcznej w pamięci podręcznej wszystkich poprzednich połączeń dla wszystkich kolejnych połączeń.

lub czy jest to tylko ostatnie połączenie, które jest buforowane?

Co jeśli napiszę leniwą funkcję biorąc drzewa jako argumenty? Czy to jest równe ? w sprawie przekazanego argumentu, aby wiedzieć, czy konieczna jest nowa ocena?

Czy to zachowanie można w jakiś sposób prześledzić w czasie wykonywania?

Odpowiedz

8

The „cache” w leniwe sekwencji nie jest zmienny cache że wygasa rzeczy, jak można wykorzystać w webapp, jest to skrzynka o wymiarach jeden i jeden jest w każdej komórce na liście. że "pamięć podręczna" zawiera wartość lub kod do obliczenia wartości, a nigdy obie. po obliczeniu wartości, która buforuje wartość (w tej komórce/wpisie) i jeśli ktokolwiek odczyta komórkę ponownie, poda im wartość bezpośrednio, zamiast wywoływać kod.

tutaj jest uproszczonym sesji urojony repl zilustrować punkt:

user> (def a (range)) 
a = [code-for-rest] 
user> (first a) 
a = [code-for-first, code-for-rest] 
a = [0, code-for-rest] 
result=> 0 
user> (first a) 
a = [0, code-for-rest] 
result=> 0 
user> (nth a 10) 
a = [0]->[1]->[2]->[3]->[4]->[5]->[6]->[7]->[8]->[9, code-for-rest] 
result=> 4 

W tym przykładzie każda komórka zawiera początkowo (i jest uproszczeniem ilustrują tylko ten punkt) kodu do generowania wartości i kod generujący resztę listy (lub zero, jeśli jest to koniec listy). gdy komórka zostanie zrealizowana (zrobiona jako niemożliwa), wówczas zastępuje jej zawartość rzeczywistą wartością, więc zawiera teraz wartość i kod generujący resztę sekwencji. Kiedy następna komórka na liście zostanie odczytana, najpierw zostanie wygenerowana przez kod dla odpoczynku (jak zawarta w komórce), wtedy kod-for-nth w nowej komórce wygeneruje wartość dla tej komórki.

+0

+1, wielkie dzięki ... Co dzieje się w przypadku "intertwinned" wzywa do funkcji leniwe (powiedz: "nth a 50", a następnie "nth a 100", a następnie "nth a 80", a następnie "nt h a 150 ")? A co z wywołaniami tej funkcji z innego wątku? Czy każdy wątek ma pamięć podręczną rozmiaru pierwszego? –

+0

@ CedricMartin Lazy Seqs, podobnie jak wszystkie inne struktury danych Clojure, są niezmienne, a zatem bezpieczne dla wątków, więc po obliczeniu zapisana wartość jest dzielona między wszystkie wątki. Pomóc może myśleć o leniwym seq jako wskaźniku do listy połączonej (dokładnie to jest), tylko ogon listy nie przejmuje się obliczaniem następnego wskaźnika, dopóki ktoś o to nie poprosi. – Alex

+0

"Pamięć podręczna" jest dosłownie w komórce listy. nie jest dołączony do żadnego konkretnego wątku. –

1

Tu masz przykład zabawkę, która pokazuje, co dzieje się w czasie wykonywania:

(defn times-two[number] 
(print "- ") 
(* 2 number)) 

(def powers-of-two (lazy-cat [1 2] (map times-two (rest powers-of-two)))) 

(println (take 10 powers-of-two)) 
(println (take 12 powers-of-two)) 

Wyjście powinno być:

(1 - 2 - 4 - 8 - 16 - 32 - 64 - 128 - 256 512)

(1 2 4 8 16 32 64 128 256 - 512 - 1024 2048)

Powiązane problemy