我想在一个使用core.async
和<!
的函数中使用memoize
。
(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
我想知道是否有更简单的方法来达到相同的结果。
**备注:我需要适用于<!>的解决方案。对于,请参阅此问题:如何备忘使用core.async和阻止通道读取的函数?**
<!!
是通过在clojure
端使用take!
和一个promise来实现的;当take!
回调触发promise时,函数才能完成。看起来有一个开源库可以将JS promises暴露给clojurescript
。你可能可以使用该库来实现<!!
。如果你在那之前没有解决,我今晚会尝试做些东西。 - Jesse Rosalia<!
必须直接从 go 块中调用(而不是从 go 块中调用的函数中调用),这限制了您定义一个 memo 函数来保存您想要保存的值的能力(即您不希望您的 memo 保存通道)。我之前提到的 promise 库使用回调和事件,对于这种情况没有用处。我的解决方案适用于clojure
,但我看不到在cljs
中使其工作的方法。 - Jesse Rosaliacore.async
团队添加memoize-async
吗? - viebelmemoize-async
这样的东西的一个缺点是,异步操作运行时间越长,冗余获取的机会就越高 - 没有存储任何内容来指示正在处理特定值的解析。之前曾经讨论过promise-chan - 你可以天真地记忆类似的东西,并且正确的事情会发生。如果您不想走promise-chan路线,还可以通过状态管理和通道多路复用变得疯狂。 - moe