使用代理在STM交易中完成副作用
-
16-10-2019 - |
题
我知道,在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,但是您可以将其变成一对,以便从计算中传递有趣的数据。
不隶属于 StackOverflow