Почему Clojure зависает после выполнения моих расчетов? - PullRequest
14 голосов
/ 12 апреля 2010

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

В любом случае, я хотел провести несколько очень простых экспериментов, где я генерирую случайные векторы и фильтрую их. Вот моя реализация, которая делает все это

(defn pfilter [pred coll]
  (map second
    (filter first
      (pmap (fn [item] [(pred item) item]) coll))))

(defn random-n-vector [n]
  (take n (repeatedly rand)))

(defn distance [u v]
  (Math/sqrt (reduce + (map #(Math/pow (- %1 %2) 2) u v))))

(defn -main [& args]
  (let [[n-str vectors-str threshold-str] args
        n (Integer/parseInt n-str)
        vectors (Integer/parseInt vectors-str)
        threshold (Double/parseDouble threshold-str)
        random-vector (partial random-n-vector n)
        u (random-vector)]
    (time (println n vectors 
      (count 
        (pfilter 
          (fn [v] (< (distance u v) threshold))
          (take vectors (repeatedly random-vector))))))))

Код выполняется и возвращает то, что я ожидаю, то есть параметр n (длина векторов), векторы (количество векторов) и количество векторов, которые ближе, чем порог к целевому вектору. Чего я не понимаю, так это почему программы зависают еще на одну минуту перед завершением.

Вот вывод прогона, который демонстрирует ошибку

$ time lein run 10 100000 1.0
     [null] 10 100000 12283
     [null] "Elapsed time: 3300.856 msecs"

real    1m6.336s
user    0m7.204s
sys 0m1.495s

Любые комментарии о том, как фильтровать параллельно в целом, также приветствуются, поскольку я еще не подтвердил, что pfilter на самом деле работает.

1 Ответ

22 голосов
/ 12 апреля 2010

Вам нужно вызвать shutdown-agents, чтобы уничтожить потоки, поддерживающие пул потоков, используемый pmap.

О pfilter, он должен работать, но работать медленнее, чем filter, поскольку ваш предикат прост. Распараллеливание не является бесплатным, поэтому вы должны дать каждому потоку умеренно интенсивные задачи, чтобы компенсировать издержки многопоточности. Пакетные вещи перед их фильтрацией.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...