Clojure — использование агентов слишком сильно замедляет выполнение

Я пишу тест для программы в Clojure. У меня есть n потоки, одновременно обращающиеся к кешу. Каждый поток будет обращаться к кешу x раз. Каждый запрос должен быть зарегистрирован в файле.

С этой целью я создал агент, который хранит путь к файлу для записи. Когда я хочу написать, я send-off использую функцию, которая записывает в файл и просто возвращает путь. Таким образом, мои записи файлов не содержат условий гонки.

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

(defn load-cache-only [usercount cache-size]
  "Test requesting from the cache only."
  ; Create the file to write the benchmark results to.
  (def sink "benchmarks/results/load-cache-only.txt")
  (let [data-agent (agent sink)
        ; Data for our backing store generated at runtime.
        store-data (into {} (map vector (map (comp keyword str)
                                             (repeat "item") 
                                             (range 1 cache-size)) 
                                        (range 1 cache-size)))
        cache      (create-full-cache cache-size store-data)]
    (barrier/run-with-barrier (fn [] (load-cache-only-work cache store-data data-agent)) usercount)))

(defn load-cache-only-work [cache store-data data-agent]
  "For use with 'load-cache-only'. Requests each item in the cache one.
   We time how long it takes for each request to be handled."
  (let [cache-size  (count store-data)
        foreachitem (fn [cache-item]
                      (let [before  (System/nanoTime)
                            result  (cache/retrieve cache cache-item)
                            after   (System/nanoTime)
                            diff_ms ((comp str float) (/ (- after before) 1000))]
                        ;(send-off data-agent (fn [filepath] 
                                           ;(file/insert-record filepath cache-size diff_ms)
                                           ;filepath))
                        ))]
    (doall (map foreachitem (keys store-data)))))

Код (barrier/run-with-barrier) просто порождает usercount потоков и запускает их одновременно (используя атом). Функция, которую я передаю, является телом каждого потока.

Тело будет просто отображать список с именем store-data, который является списком ключ-значение (например, {:a 1 :b 2}. Длина этого списка в моем коде прямо сейчас составляет 10. Количество пользователей также равно 10.

Как видите, код отправки агента закомментирован. Это заставляет код выполняться нормально. Однако, когда я включаю отправку, даже без записи в файл, время выполнения слишком медленное.

Редактировать:

Я заставил каждую ветку, прежде чем он отправится к агенту, поставить точку. Точки появляются так же быстро, как и без проводов. Так что должно быть что-то блокирующее в конце.

Я делаю что-то неправильно?


person Christophe De Troyer    schedule 02.05.2014    source источник


Ответы (1)


Вам нужно вызвать (shutdown-agents), когда вы закончите отправлять данные своему агенту, если вы хотите, чтобы JVM завершила работу в разумные сроки.

Основная проблема заключается в том, что если вы не отключите свои агенты, потоки, поддерживающие его пул потоков, никогда не будут закрыты и предотвратят выход JVM. Есть тайм-аут, который отключит пул, если больше ничего не работает, но он довольно длительный. Вызов shutdown-agents, как только вы закончите производить действия, решит эту проблему.

person Jacek Lach    schedule 02.05.2014
comment
Это действительно решило мою проблему. Виртуальная машина немедленно отключается при выполнении этой команды! Большое тебе спасибо! :) - person Christophe De Troyer; 02.05.2014
comment
Я мог бы добавить: у меня есть два теста, в каждом из которых используется агент. Когда каждый тестовый вызов (shutdown-agents) действует одинаково. Вызов (агентов отключения) после завершения всех тестов сделал свое дело! - person Christophe De Troyer; 02.05.2014