Clojure różnice między Ref, Var, Agent, Atom, z przykładami

110

Jestem bardzo nowy w Clojure. Czy możecie mi wyjaśnić na podstawie rzeczywistych scenariuszy. Mam na myśli, gdzie użyć Ref, Var, Agent, Atom. Czytałem książkę, ale nadal nie mogłem zrozumieć przykładów z prawdziwego świata.

Mikrofon
źródło

Odpowiedzi:

174

Gorąco polecam "The Joy of Clojure" lub "Programowanie Clojure", aby uzyskać prawdziwą odpowiedź na to pytanie, mogę odtworzyć krótki fragment motywacji dla każdego z nich:

zacznij od obejrzenia tego filmu na temat tożsamości i / lub studiowania tutaj .

  • Odniesienia dotyczą skoordynowanego synchronicznego dostępu do „wielu tożsamości”.
  • Atomy służą do nieskoordynowanego, synchronicznego dostępu do pojedynczej tożsamości.
  • Agenci służą do nieskoordynowanego asynchronicznego dostępu do pojedynczej tożsamości.
  • Zmienne są przeznaczone dla lokalnych izolowanych tożsamości wątków ze wspólną wartością domyślną.

Skoordynowany dostęp jest używany, gdy dwie Tożsamości muszą się zmienić razem, klasycznym przykładem jest przenoszenie pieniędzy z jednego konta bankowego na drugie, muszą one zostać przeniesione całkowicie lub wcale.

Nieskoordynowany dostęp jest używany, gdy tylko jedna tożsamość wymaga aktualizacji, jest to bardzo częsty przypadek.

Dostęp synchroniczny jest używany, gdy połączenie ma czekać, aż wszystkie tożsamości zostaną rozliczone, zanim będzie kontynuowane.

Dostęp asynchroniczny to „odpal i zapomnij” i pozwala Tożsamości osiągnąć nowy stan we własnym czasie.

Arthur Ulfeldt
źródło
W dostępie skoordynowanym, jeśli chcę tylko zmienić state-a, ale odnosić się do state-btego, nadal potrzebuję refpoprawnego? Czyli nie zmienia wielu rzeczy, ale odnosi się do wielu rzeczy, zmieniając dowolną z nich?
event_jr
2
Tak, wydaje się, że dobrze rozumiesz, że oba stan-a i stan-b muszą być referencjami.Jeśli chcesz, aby nowa wartość w stanie-a była oparta na spójnej kombinacji wartości w a i b. Potrzebujesz, aby ta nowa wartość została obliczona w kontekście, w którym stan-a i stan-b są zgodne ze sobą. Gdy oba są referencjami, jeśli b zmieni się w połowie, transakcja zostanie wznowiona i użyje nowych wartości zarówno a, jak i b. rozważ użycie ensurefunkcji: clojure.github.io/clojure/clojure.core-api.html#clojure.core/, aby uczynić to wyraźnym i bardziej wydajnym.
Arthur Ulfeldt
3
Może można dodać wyjaśnienie, co izolowane ze współdzielonymi domyślnymi środkami, aby uzupełnić odpowiedź?
Didier A.,
1
„Dostęp skoordynowany jest używany, gdy dwie Tożsamości muszą zostać zmienione razem…”. Czy należy to „zmienić”?
Carcigenicate
40

Odniesienia dotyczą stanu, który musi być zsynchronizowany między wątkami. Jeśli chcesz śledzić kilka różnych rzeczy, a czasami będziesz musiał wykonać operacje, które zapisują kilka rzeczy naraz, użyj refs. Za każdym razem, gdy masz wiele różnych stanów, używanie referencji nie jest złym pomysłem.

Atomy są dla niezależnego stanu, który należy zsynchronizować między wątkami. Jeśli nigdy nie będziesz musiał zmieniać stanu atomu i czegokolwiek innego w tym samym czasie, użycie at atom jest bezpieczne (w szczególności, jeśli w całym programie jest tylko jeden element stanu, możesz umieścić go w atomie) . Jako nietrywialny przykład, jeśli próbujesz buforować wartości zwracane funkcji (tj. Zapamiętać ją), użycie atomu jest prawdopodobnie bezpieczne - stan jest niewidoczny dla wszystkiego poza funkcją, więc nie musisz się martwić o zmianie stanu wewnątrz funkcji, która coś psuje.

Głównym punktem agentów jest to, że działają w innym wątku. Możesz uzyskać wartość agenta i powiedzieć mu, aby zastosował funkcję do jego wartości, ale nie wiesz, kiedy funkcja zostanie uruchomiona ani do jakiej wartości zostanie zastosowana.

Zmienne są używane, gdy musisz przechowywać coś na podstawie wątku. Jeśli masz program wielowątkowy i każdy wątek potrzebuje własnego stanu prywatnego, umieść ten stan w zmiennej.

Jeśli chodzi o przykłady ze świata rzeczywistego, jeśli podasz przykład tego, co próbujesz zrobić, możemy Ci powiedzieć, czego użyć.

Retief
źródło
32

Kiedy po raz pierwszy przeczytałem o tych typach, starałem się również zrozumieć, gdzie mogę lub powinienem używać każdego z nich, więc oto moja prosta angielska odpowiedź:

Użyj zmiennej, jeśli dane nie ulegną zmianie. Dzieje się tak, gdy używasz deflub większość funkcji, które zaczynają się defniczym defn.

Użyj atomu, jeśli masz jeden element, który się zmienia. Przykładem może być licznik lub wektor, do którego chcesz dodać elementy.

Użyj ref, jeśli masz dwie lub więcej rzeczy, które muszą się zmienić w tym samym czasie. Pomyśl o „transakcjach baz danych”, jeśli znasz. Kanonicznym przykładem tego jest przelewanie pieniędzy z jednego konta na drugie. Każde konto może być przechowywane w referencji, aby zmiany wyglądały niepodzielnie.

Skorzystaj z usług agenta, jeśli chcesz coś zmienić, ale nie obchodzi Cię kiedy. Może to być długie obliczenia lub zapisywanie czegoś do pliku lub gniazda. Zauważ, że z tym drugim powinieneś użyć send-off.

Uwaga: doceniam, że w każdym z nich jest o wiele więcej, ale mam nadzieję, że powinno to dać ci punkt wyjścia.

optevo
źródło
1
Wielkie dzięki za jasną odpowiedź :-) Bardzo pomaga nowicjuszowi Clojure, takiemu jak ja.
gosukiwi
27

Napisałem artykuł podsumowujący różnice między nimi i pomagający wybrać, kiedy z nich skorzystać.

Udostępnij stan - kiedy używasz zmiennych, atomów, agentów i referencji?

Mam nadzieję, że pomoże to ludziom szukającym odpowiedzi w tym temacie.

Kilka skrótów z artykułu po sugestii @tunaci:

Vars

Vars są globalne dla każdego wątku.

Nie zmieniaj zmiennych po utworzeniu. Jest to technicznie możliwe, ale z wielu powodów jest to zły pomysł.

Atomy

Udostępnij dostęp do zmiennego stanu dla każdego wątku. Zmiana zachodzi synchronicznie. Spróbuj ponownie, gdy inny wątek zmieni stan podczas uruchamiania.

Nie używaj funkcji nie idempotentnych i funkcji z długim czasem wykonywania

Agenci

Udostępnij dostęp do zmiennego stanu dla każdego wątku. Zmiana zachodzi asynchronicznie.

Nr ref

Refs działa podobnie do transakcji w bazie danych. Zapis i odczyt są chronione w dosync. Możesz operować na wielu referencjach bezpiecznych w transakcji.

I schemat blokowy, gdy używamy którego: schemat blokowy

Proszę spojrzeć na obraz na stronie internetowej, ponieważ zawsze możliwe są aktualizacje.

Udzielenie pełnej odpowiedzi bez kopiowania i poprzedniego artykułu jest złożonym i długim tematem, więc wybaczcie mi, że przekierowuję na stronę internetową :)

kabra
źródło