How to memoize a function that uses core.async and blocking channel read?

佐手、 提交于 2019-12-08 08:21:25

问题


I'd like to use memoize for a function that uses core.async and <!! e.g

(defn foo [x]
  (go
    (<!! (timeout 2000))
    (* 2 x)))

(In the real-life, it could be useful in order to cache the results of server calls)

I was able to achieve that by writing a core.async version of memoize (almost the same code as memoize):

(defn memoize-async [f]
  (let [mem (atom {})]
    (fn [& args]
      (go
        (if-let [e (find @mem args)]
          (val e)
         (let [ret (<! (apply f args))]; this line differs from memoize [ret (apply f args)]
            (swap! mem assoc args ret)
            ret))))))

Example of usage:

(def foo-memo (memoize-async foo))
(go (println (<!! (foo-memo 3)))); delay because of (<!! (timeout 2000))

(go (println (<!! (foo-memo 3)))); subsequent calls are memoized => no delay

I am wondering if there are simpler ways to achieve the same result.

Remark: I need a solution that works with <!!. For <!, see this question: How to memoize a function that uses core.async and non-blocking channel read?


回答1:


You can use the built in memoize function for this. Start by defining a method that reads from a channel and returns the value:

 (defn wait-for [ch]
      (<!! ch))

Note that we'll use <!! and not <! because we want this function block until there is data on the channel in all cases. <! only exhibits this behavior when used in a form inside of a go block.

You can then construct your memoized function by composing this function with foo, like such:

(def foo-memo (memoize (comp wait-for foo)))

foo returns a channel, so wait-for will block until that channel has a value (i.e. until the operation inside foo finished).

foo-memo can be used similar to your example above, except you do not need the call to <!! because wait-for will block for you:

(go (println (foo-memo 3))

You can also call this outside of a go block, and it will behave like you expect (i.e. block the calling thread until foo returns).



来源:https://stackoverflow.com/questions/24781858/how-to-memoize-a-function-that-uses-core-async-and-blocking-channel-read

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!