Frage

Mir ist bewusst, dass es im Allgemeinen eine schlechte Praxis ist, Funktionen mit Nebenwirkungen innerhalb von STM-Transaktionen zu setzen, da sie möglicherweise mehrmals wiedergegeben und aufgerufen werden können.

Es fällt mir jedoch ein, dass Sie Agenten verwenden können, um sicherzustellen, dass die Nebenwirkungen erst nach erfolgreichem Abschluss der Transaktion ausgeführt werden.

z.B

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

Ist diese gute Praxis?

Was sind die Vor-/Nachteile/Fallstricke?

War es hilfreich?

Lösung

Original:

Es scheint mir so zu sein. Je nachdem, was Ihre Nebenwirkungen sind, möchten Sie möglicherweise Send-Off (für IO-gebundene OPs) anstelle von Senden (für CPU-gebundene OPs) verwenden. Mit dem Senden/Senden wird die Aufgabe in einen der internen Beamten des internen Agenten-Ausführenden eingeteilt (es gibt einen Pool fester Größenpool für CPU und unbegrenzter Größenpool für IO-OPs). Sobald die Aufgabe aufgetreten ist, ist die Arbeit aus dem Dosync -Thread, sodass Sie zu diesem Zeitpunkt getrennt sind.

Sie müssen alle Werte erfassen, die Sie innerhalb der Transaktion in die gesendete Funktion benötigen. Und Sie müssen sich mit diesem Versand befassen, der möglicherweise aufgrund von Wiederholungen mehrfach auftritt.

Update (siehe Kommentare):

Agent sendet innerhalb der Transaktion des Refs, bis die REF -Transaktion erfolgreich abgeschlossen und einmal ausgeführt wird. In meiner obigen Antwort tritt der Send also nicht mehrmals auf, aber er wird während der Ref-Transaktion nicht auftreten, was möglicherweise nicht das ist, was Sie wollen (wenn Sie erwarten, dass Sie sich protokollieren oder Nebeneffekte durchführen).

Andere Tipps

Dies funktioniert und ist üblich. Wie Alex jedoch zu Recht darauf hingewiesen hat, sollten Sie über den Senden nachdenken.

Es gibt mehr Möglichkeiten, um Spitzenwerte zu erfassen und sie aus der Transaktion zu verteilen. Sie können sie beispielsweise in einem Vektor (oder einer Karte oder was auch immer) zurückgeben.

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

Oder Sie können Reset anrufen! auf einem lokalen Atom (definiert außerhalb des lexikalischen Umfangs des dosynchronen Blocks).

Die Verwendung von Agenten ist nichts Falsches, aber einfach aus den Transaktionswerten, die für die Nebeneffektberechnung erforderlich sind, reicht häufig aus.

Refs sind wahrscheinlich der sauberste Weg, dies zu tun, aber Sie können es sogar mit nur Atomen bewältigen!

(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"))))

Das swap! Kann nach Bedarf so oft wiederholen, aber die Arbeitswarteschlange wird nie größer als drei, und Sie werden immer drucken genau einmal Eine Nachricht, die korrekt an die Annahme Ihres Arbeitselements gebunden ist. Das "Original -Design" forderte nur ein einzelnes INT im Atom, aber Sie können es in ein Paar verwandeln, um interessante Daten aus der Berechnung zurückzugeben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top