Concurrency 如何结合非尾部递归+;有效且同步的回忆录+;Clojure中的有界堆栈消耗?
在Clojure中,如何将非尾部递归与同步记忆和有界堆栈消耗(因此没有堆栈溢出的风险)结合起来?所谓同步备忘录化,我的意思是备忘录/缓存必须在线程之间并发高效地共享 我的具体情况如下:Concurrency 如何结合非尾部递归+;有效且同步的回忆录+;Clojure中的有界堆栈消耗?,concurrency,clojure,synchronization,stack-overflow,memoization,Concurrency,Clojure,Synchronization,Stack Overflow,Memoization,在Clojure中,如何将非尾部递归与同步记忆和有界堆栈消耗(因此没有堆栈溢出的风险)结合起来?所谓同步备忘录化,我的意思是备忘录/缓存必须在线程之间并发高效地共享 我的具体情况如下: ; g() is non recursive ; i is an integer ; h is a hash with int keywords and vector of ints values ; w is a hash with int keywords and int values (defn g [i
; g() is non recursive
; i is an integer
; h is a hash with int keywords and vector of ints values
; w is a hash with int keywords and int values
(defn g [i h w]
(filter
#(-> (w %)
(= i))
(h i)))
; f is recursive, recurses non-trivially (non-tail, multiple times)
; TODO: be memoizable (ideally in a synchronized way, for parallelism)
; TODO: pose no risk stack overflow
(defn f [i h w]
(if (nil? (h i))
0
(let [part_sum
(map ; will change this map to pmap or pvmap
#(f % h w)
(g i h))]
(-> (reduce + part_sum)
(/ 2)
(+ 1)))))
; trivial, shown for completeness
(defn ff [i h w]
(-> (f i h w)
(- 1)
(* 2)
(max 0)))
幸运的是,这些问题可以独立解决:
(def memoized-function (memoize function-name))
它几乎适用于所有情况。如果您需要其他选项,则使您希望记忆的功能返回一个未来
,而不是结果,并且在使用它们之前只deref
从缓存中获取的值
对于选项二,内置的trampoline
函数允许您使用常量堆栈非尾部递归函数。在基本情况下(当递归完成时),您可以更改函数以返回一个不是函数的值(只是一个正常结果),并在需要进一步递归时返回一个函数。然后,trampoline
函数反复“反弹”到函数中,直到值从另一侧掉出来。看起来是这样的:
user> (defn foo-helper [x]
(let [result
(if (pos? x)
#(foo-helper (dec x))
x)]
(println "foo" x)
result))
#'user/foo-helper
user> (trampoline foo-helper 4)
foo 4
foo 3
foo 2
foo 1
foo 0
0
因此,您可以将Clojure的正常缓存与正常的trampline函数调用结合起来,而不必担心关于记忆的“线程安全”问题:从机罩下的core lib atom开始,所以它应该是线程安全的,我相信避免堆栈溢出:这是一个一般性问题,不是Clojure特有的。您可以找到一些解决此问题的通用方法。