Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Concurrency 如何结合非尾部递归+;有效且同步的回忆录+;Clojure中的有界堆栈消耗?_Concurrency_Clojure_Synchronization_Stack Overflow_Memoization - Fatal编程技术网

Concurrency 如何结合非尾部递归+;有效且同步的回忆录+;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

在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 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)))

幸运的是,这些问题可以独立解决:

  • 一致的共享内存化缓存
  • 无需吹扫堆栈的无尾递归迭代
  • 对于问题1,您需要首先确定应该在什么位置填充缓存。应该在开始计算函数时填充它。这意味着应该绝对保证每个函数只运行一次,即使在第一个函数运行时进行了第二次调用。或者,如果您希望允许两个函数调用同时发生,并且只将其中一个存储到缓存中。这方面的一个细微变化是,您只需将最后返回的结果存储到缓存中

    最后一种方法是默认情况下您只需调用

    (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特有的。您可以找到一些解决此问题的通用方法。