metaclass: (Default)
metaclass ([personal profile] metaclass) wrote2013-03-26 09:25 pm
Entry tags:

Clojure, ленивость и отложенные отчеты

Очередной раз стукнулся об ленивость.

Делаю фоновый расчет отчетов - клиент просит у сервиса "посчитай мне отчет", тот ему возвращает идентификатор-ссылку на future со считалкой отчета и далее клиент опрашивает сервис на предмет "а не готов ли наш отчет" и тот ему отвечает либо "не готов" либо "готов, вот тебе данные".
Ну, склепал очередь отчетов - атом, в нем мап, в мапе идентификаторы запрошенных отчетов и future к ним. Запускаю - а оно мгновенно говорит, "да, вот отчет готов, забирай" и давай его считать и отдавать. В потоке запроса, не в рабочем потоке future.
Ленивость. Оно возвращает башку последовательности данных отчета сразу, "на тэбэ, дорогой, форси меня". И запрос готовых данных (в том числе, даже просто попытка в целях отладки посмотреть на мап с future) - вызывает форсинг последовательности.

PS: И еще обнаружил очередную фичу кложури - thread-local bindings протаскиваются во все вызовы, которые перекладывают работу в другие потоки. Т.е. конкретно тут - я в запросе часть общих параметров (типа имени пользователя) складываю в thread-local binding чтобы не протаскивать их руками через 100500 функций, думал, что при вычислении внутри future придется их доставать и перекладывать во второй поток - а оно уже сделано.
Авторы кложури не перестают удивлять своей крайней адекватностью и практичностью языка.

[identity profile] tonsky.livejournal.com 2013-03-27 06:38 am (UTC)(link)
Насколько я помню по реализации, только если запускаешь вычисления через Future или Agent. Мы как-то стартовали треды сами и выковыривали соответствующий код из clojure.core чтобы оно так же работало. Появилось, кстати, недавно, в 1.3 или 1.4

[identity profile] metaclass.livejournal.com 2013-03-27 06:44 am (UTC)(link)
Да, в 1.3 и при запуске стандартными средствами.
А разве 1.3 это недавно? Я вроде 1.4 год назад начал использовать, 1.5 недавно вышла.

[identity profile] prepor.livejournal.com 2013-03-30 02:52 pm (UTC)(link)
эм, простите, вы разве не про это?

(def ^:dynamic *foo*)
(binding [*foo* "bar"]
	       (-> (Thread. (bound-fn [] (prn *foo*)))
		   (.start)))

=> "bar"
Edited 2013-03-30 14:52 (UTC)