Имеет ли смысл запоминать обещания?

Я использую HTTP Kit для отправки запросов, и я хочу, чтобы они были асинхронными, но я также хочу кэшировать ответы. Причина, по которой я хочу, чтобы запросы были асинхронными, заключается в том, что я делаю несколько запросов одновременно и хочу, чтобы они работали параллельно.

Вот моя функция, которая делает несколько запросов параллельно.

(defn parallel-requests-1 [urls]
  (let [; Dispatch all requests to run concurrently.
        responses (doall (map #(http/get %) urls))
        ; Realise all promises.
        realised (doall (map deref responses))
        ; Extract response body.
        bodies (map :body realised)]
    bodies))

(parallel-requests-1 ["http://example.com", "http://example.net"])

Это сделано исключительно в иллюстративных целях, чтобы продемонстрировать, что я не хочу просто deref давать обещание и запоминать его.

Теперь я хочу добавить кеширование с помощью memoize. Я пробовал это:

(def memoized-get (memoize http/get))

(defn parallel-requests-2 [urls]
  (let [; Dispatch all requests to run concurrently.
        responses (doall (map #(memoized-get %) urls))
        ; Realise all promises.
        realised (doall (map deref responses))
        ; Extract response body.
        bodies (map :body realised)]
    bodies))

Все признаки показывают, что это работает хорошо.

Это разумное решение? Меня беспокоит то, что кэширование промиса может привести к утечке ресурсов.


person Joe    schedule 28.07.2015    source источник
comment
Гораздо разумнее запоминать промисы, чем запоминать значение, потому что таким образом у вас не будет состояния гонки на случай, если кто-то запустит операцию несколько раз, поскольку запоминание произойдет, когда операция начнется, а не когда она закончится.   -  person Benjamin Gruenbaum    schedule 28.07.2015
comment
Кроме того, кэшированное обещание будет содержать больше информации, чем его результат. В случае отклонения он даст вам доступ к причине отклонения, что может быть полезно при некоторых обстоятельствах. Например, вы можете повторить попытку, если удаленная служба была недоступна, но не повторять попытку, если причиной был нулевой результат. Или вы можете просто захотеть зарегистрировать/отобразить причину (снова).   -  person Roamer-1888    schedule 28.07.2015
comment
Промисы уже запоминают свои результаты — мне не ясно, чего вы надеетесь достичь с помощью вызова memoize.   -  person schaueho    schedule 28.07.2015
comment
Промисы запоминают свои собственные результаты, но вызов http/get каждый раз возвращает другой промис и, таким образом, приводит к новому запросу. Я хочу кэшировать результат http/get, т.е. хранить каждое результирующее обещание.   -  person Joe    schedule 28.07.2015
comment
связанные: Запоминание функции на основе обещаний   -  person Bergi    schedule 30.07.2015
comment
Спасибо @Берги. Я видел это, но мой вопрос был о механике реализации clojure в отношении возможных утечек ресурсов и т. д., а не о принципе кэширования обещаний.   -  person Joe    schedule 30.07.2015


Ответы (1)


Да, имеет смысл запомнить обещание. На самом деле, это, наверное, самое разумное решение в данной ситуации. В конце концов, это то, что возвращает http/get, и это функция, которую вы хотите запомнить.

Что касается утечки ресурсов, это не должно быть проблемой больше, чем обычно, независимо от того, запоминаете ли вы обещание или его значение. Обещание — это, по сути, просто некоторое состояние, которое ссылается на значение после того, как оно deliver!ed. Таким образом, у вас есть небольшие накладные расходы для этой ссылки, но они ничтожны по сравнению со всем ответом.

person Nathan Davis    schedule 30.07.2015
comment
Спасибо большое. В прошлом у меня был ограниченный запас chans (поток просто блокировался, когда я пытался создать слишком много), поэтому я хотел быть уверенным. У меня пока не было проблем с кэшированием обещаний (хотя прошел всего день). - person Joe; 30.07.2015