我想将memoize
用于使用core.async
和<!!
的功能,例如
(defn foo [x]
(go
(<!! (timeout 2000))
(* 2 x)))
(在现实生活中,它可能有助于缓存服务器调用的结果)
我能够通过编写memoize的core.async版本来实现这一点(几乎与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))))))
使用示例:
(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
我想知道是否有更简单的方法可以达到相同的效果。
备注:我需要一个适用于<!!
的解决方案。对于<!
,请参阅此问题:How to memoize a function that uses core.async and non-blocking channel read?
答案 0 :(得分:4)
您可以使用内置的memoize功能。首先定义一个从通道读取并返回值的方法:
(defn wait-for [ch]
(<!! ch))
请注意,我们会使用<!!
而不是<!
,因为我们需要此功能块,直到所有情况下都有通道上的数据。 <!
仅在go块内的表单中使用时才会出现此行为。
然后,您可以通过将此函数与foo
组合来构建您的memoized函数,如下所示:
(def foo-memo (memoize (comp wait-for foo)))
foo
会返回一个频道,因此wait-for
会阻止,直到该频道有一个值(即直到foo
内的操作完成)。
foo-memo
可以与您上面的示例类似,但您不需要调用<!!
,因为wait-for
会阻止您:
(go (println (foo-memo 3))
你也可以在go块之外调用它,它会表现得像你期望的那样(即阻止调用线程直到foo返回)。