Как запомнить функцию, которая использует core.async и блокирует чтение канала?
Я хотел бы использовать 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
Мне интересно, есть ли более простые способы достичь того же результата.
Примечание: мне нужно решение, которое работает с <!!
, За <!
см. вопрос: Как запоминать функцию, которая использует core.async и неблокирующее чтение канала?
1 ответ
Вы можете использовать встроенную функцию памятки для этого. Начнем с определения метода, который читает канал и возвращает значение:
(defn wait-for [ch]
(<!! ch))
Обратите внимание, что мы будем использовать <!!
и не <!
потому что мы хотим этот функциональный блок, пока не будет данных на канале во всех случаях. <!
это поведение проявляется только при использовании в форме внутри блока go.
Затем вы можете создать свою запомненную функцию, составив эту функцию с foo
вот так:
(def foo-memo (memoize (comp wait-for foo)))
foo
возвращает канал, так wait-for
будет блокироваться, пока этот канал не будет иметь значение (то есть, пока операция внутри foo
законченный).
foo-memo
можно использовать аналогично вашему примеру выше, за исключением того, что вам не нужен вызов <!!
так как wait-for
заблокирует для вас:
(go (println (foo-memo 3))
Вы также можете вызвать это вне блока go, и он будет вести себя так, как вы ожидаете (т.е. блокировать вызывающий поток до тех пор, пока foo не вернется).