我知道,在STM交易中添加副作用的功能通常是不好的做法,因为它们可能会被重复并多次被调用。

然而,在我看来,您可以使用代理来确保仅在交易成功完成后才执行副作用。

例如

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

这是好习惯吗?

什么是利于/缺点/陷阱?

有帮助吗?

解决方案

原来的:

好像这应该对我有用。根据您的副作用是什么,您可能需要使用发送(用于IO-BOND OPS)而不是发送(用于CPU结合OPS)。发送/发送将使任务将任务加入一个内部代理执行池之一(CPU有一个固定尺寸的池和IO OPS的无界尺寸池)。一旦任务被重新加入,该工作就脱离了dosync的线程,因此您当时已断开连接。

当然,您需要从交易中捕获所需的任何值。而且,您需要处理由于检索而可能发生多次发送的发送。

更新(请参阅评论):

在REF的交易中发送代理商发送,直到Ref交易成功完成并执行一次。因此,在上面的回答中,发送不会多次发生,但是在参考资料期间不会发生这种情况,这可能不是您想要的(如果您期望登录或做副作用的东西)。

其他提示

这是有效的,是常见的实践。但是,就像Alex正确指出的那样,您应该考虑发送发送。

还有更多方法可以捕获有限的价值并将其从交易中分发出来。例如,您可以将它们返回向量(或地图或其他任何内容)。

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

或者您可以致电重置!在局部原子上(当然是在dosync块的词汇范围之外定义的)。

使用代理没有错,但是仅仅从副作用计算所需的交易值返回通常就足够了。

裁判可能是最干净的方法,但您甚至可以仅使用原子进行管理!

(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! 可以根据需要重试的次,但是工作队列永远不会大于三,您将始终打印 完全是一次 与接受您的工作项目正确息息相关的消息。 “原始设计”只需在原子中使用一个INT,但是您可以将其变成一对,以便从计算中传递有趣的数据。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top