2011-01-22 19 views
7

Jestem świadomy, że generalnie złym zwyczajem jest umieszczanie funkcji z efektami ubocznymi w transakcjach STM, ponieważ mogą one potencjalnie być wielokrotnie ponawiane i wywoływane.Używanie agentów do uzupełniania efektów ubocznych w transakcjach STM

Wydaje mi się jednak, że można użyć agentów, aby zapewnić, że efekty uboczne zostaną wykonane dopiero po pomyślnym zakończeniu transakcji.

np.

(dosync 
    // transactional stuff 
    (send some-agent #(function-with-side-effects params)) 
    // more transactional stuff 
) 

Czy to dobra praktyka?

Jakie są zalety/wady/pułapki?

+0

Jedną z podstawowych idei STM jest brak atomowości. Jak by to pomogło w tym? –

+0

Chodzi o efekty uboczne, które muszą wystąpić po pomyślnej transakcji, ale same nie są częścią transakcji, np. wysyłanie wiadomości e-mail z potwierdzeniem. Oczywiście, nie chcesz tego robić za każdym razem, gdy ponawiasz próbę transakcji, bo inaczej możesz dostać bardzo złego/zdezorientowanego odbiorcę! – mikera

Odpowiedz

6

oryginalny:

Wydaje się, że należy dążyć do mnie. W zależności od tego, jakie są twoje efekty uboczne, możesz użyć funkcji wysyłania (dla opętanych przez IO) zamiast wysyłać (dla operacji związanych z cpu). Wysłanie/wysłanie spowoduje umieszczenie zadania w jednej z wewnętrznych pul wykonawczych agenta (istnieje puli o ustalonym rozmiarze dla procesora i nieograniczonej puli wielkości dla operacji io). Po zaksięgowaniu zadania praca jest wyłączona z wątku dosync, więc w tym momencie jesteś odłączony.

Będziesz musiał przechwycić wszystkie potrzebne wartości z transakcji do wysłanej funkcji oczywiście. I musisz radzić sobie z tym wysyłaniem, które może występować wiele razy z powodu prób.

Update (patrz komentarze):

agent wysyła wewnątrz transakcji ref są utrzymywane aż transakcja ref pomyślnie zakończona i są wykonywane raz. Tak więc w powyższej odpowiedzi wysyłanie NIE wystąpi wiele razy, ale nie pojawi się podczas transakcji ref, która może nie być tym, czego potrzebujesz (jeśli spodziewasz się zalogować lub zrobić rzeczy o bocznym efekcie).

+0

@mikera, @Alex, wysyłanie jest gwarantowane tylko raz, gdy transakcja powiedzie się i nie powinno następować wiele razy. (Oświadczenie 5 w http://clojure.org/agents) – bmillare

+0

@bmillare - Myślę, że mówisz o czymś innym. To stwierdzenie odnosi się do tego, w jaki sposób zostanie wykonana funkcja przekazana w wysyłaniu/wysyłaniu. To, co mówię, polega na tym, że wywołując to wywołanie w transakcji ref, operacja * ref może być powtórzona, powodując wiele wywołań wysyłania/wysyłania, z których każdy jest wykonywany dokładnie raz. –

+0

@alex, przepraszam, odniosłem się do niewłaściwego punktu, dalej w tekście, mówi: "Agenci są zintegrowani ze STM - wszelkie wywołania wykonane w transakcji są utrzymywane do momentu zatwierdzenia i są odrzucane, jeśli zostaną ponowione lub przerwane. " – bmillare

5

To działa i jest powszechną praktyką. Jednak, jak słusznie zauważył Alex, powinieneś rozważyć wysłanie go przez wysłanie.

Istnieje więcej sposobów przechwytywania wartości zatwierdzonych i wydawania ich z transakcji. Na przykład możesz zwrócić je w wektorze (lub mapie lub cokolwiek innego).

(let [[x y z] (dosync 
       ; do stuff 
       [@x @y @z])] ; values of interest to sode effects 
    (side-effect x y z)) 

lub możesz zadzwonić reset! na lokalnym atomie (zdefiniowanym poza zakresem leksykalnym bloku dosync oczywiście).

1

Nie ma nic złego w używaniu agentów, ale po prostu wracając z wartości transakcji potrzebnych do obliczania efektów ubocznych, często wystarcza.

Refs to prawdopodobnie najczystszy sposób, aby to zrobić, ale możesz nawet nim zarządzać za pomocą tylko atomów!

(def work-queue-size (atom [0])) 

(defn add-job [thunk] 
    (let [[running accepted?] 
     (swap! work-queue-size 
       (fn [[active]] 
       (if (< active 3) 
        [(inc active) true] 
        [active false])))] 
    (println 
    (str "Your job has been " 
      (if accepted? 
      "queued, and there are " 
      "rejected - there are already ") 
      running 
      " total running jobs")))) 

swap! można powtórzyć tyle razy, ile potrzeba, ale kolejka praca nigdy nie będzie większa niż trzy, a będziesz zawsze drukować dokładnie raz wiadomość, która jest związana poprawnie z akceptacją swojej pozycji roboczej . "Oryginalny projekt" wymagał tylko jednego atomu w atomie, ale można go przekształcić w parę w celu przekazania interesujących danych z obliczeń.