Размер папки вычислений

Я пытаюсь вычислить размер папки параллельно. Может это наивный подход. Что я делаю, так это то, что я передаю вычисление каждого узла ветви (каталога) агенту. Все листовые узлы имеют свои размеры файлов, добавленные к my-size. Что ж, это не работает. :)

"сканирование" работает нормально, серийно. «pscan» печатает только файлы с первого уровня.

(def agents (atom []))
(def my-size (atom 0))
(def root-dir (clojure.java.io/file "/"))

(defn scan [listing]
  (doseq [f listing]
    (if (.isDirectory f)
      (scan (.listFiles f))
      (swap! my-size #(+ % (.length f))))))

(defn pscan [listing]
  (doseq [f listing]
    (if (.isDirectory f)
      (let [a (agent (.listFiles f))]
        (do (swap! agents #(conj % a))
            (send-off a pscan)
            (println (.getName f))))
    (swap! my-size #(+ %  (.length f))))))

Ты хоть представляешь, что я сделал не так?

Спасибо.


person jppalencar    schedule 03.05.2011    source источник


Ответы (2)


Нет необходимости сохранять состояние с помощью атомов. Чистый функционал:

(defn psize [f]
  (if (.isDirectory f)
    (apply + (pmap psize (.listFiles f)))
    (.length f)))
person Jürgen Hötzel    schedule 03.05.2011
comment
Новичок - это постоянное состояние ума при выполнении lisp / clojure;) Спасибо. - person jppalencar; 03.05.2011
comment
ürgenHötzel: Ну, это немного вдохновило. Но когда вы прочитаете clojure / docs, вы обнаружите, что pmap - это ... Полезно только для вычислительно интенсивных функций, где время f доминирует над накладными расходами на координацию. Решение вычисления размера папки, с моей точки зрения точки зрения - это скорее проблема производителя / потребителя. Когда производители разделяют корневой каталог на узлы ветвей, а потребители подсчитывают размеры файлов из этих ветвей. Это больше похоже на настройку правильного размера проблемы. Меня вдохновил другой пост - person jppalencar; 04.05.2011

Значит, параллельный подсчет размера файлов должен быть таким простым?

Это не :)

Я попытался решить эту проблему лучше. Я понял, что делаю блокировку операций ввода-вывода, поэтому pmap не выполняет эту работу. Я подумал, что, возможно, будет иметь смысл предоставление агентам кусков каталогов (веток) для их независимой обработки. Похоже, да :) Ну, я еще не тестировал.

Это работает, но могут возникнуть проблемы с символическими ссылками в UNIX-подобных системах.

(def user-dir (clojure.java.io/file "/home/janko/projects/"))
(def root-dir (clojure.java.io/file "/"))
(def run? (atom true))
(def *max-queue-length* 1024)
(def *max-wait-time* 1000)    ;; wait max 1 second then process anything left
(def *chunk-size* 64)
(def queue (java.util.concurrent.LinkedBlockingQueue. *max-queue-length* ))
(def agents (atom []))
(def size-total (atom 0))
(def a (agent []))

(defn branch-producer [node]
  (if @run?
    (doseq [f node]
      (when (.isDirectory f)
    (do (.put queue f)
        (branch-producer (.listFiles f)))))))

(defn producer [node]
  (future
    (branch-producer node)))

(defn node-consumer [node]
  (if (.isFile node)
    (.length node)
    0))

(defn chunk-length []
  (min (.size queue) *chunk-size*))

(defn compute-sizes [a]
  (doseq [i (map (fn [f] (.listFiles f)) a)]
    (swap! size-total #(+ % (apply + (map node-consumer i))))))

(defn consumer []
  (future
    (while @run?
      (when-let [size (if (zero? (chunk-length))
            false
            (chunk-length))] ;appropriate size of work
      (binding [a (agent [])]                    
        (dotimes [_ size]         ;give us all directories to process
          (when-let [item (.poll queue)]
            (set! a (agent (conj @a item)))))
        (swap! agents #(conj % a))
        (send-off a compute-sizes))
      (Thread/sleep *max-wait-time*)))))

Вы можете запустить его, набрав

    (producer (list user-dir))
    (consumer)

Для типа результата

    @size-total

Вы можете остановить это (есть работающие фьючерсы - поправьте меня, если я ошибаюсь)

    (swap! run? not)

Если вы обнаружите какие-либо ошибки / ошибки, пожалуйста, поделитесь своими идеями!

person jppalencar    schedule 04.05.2011
comment
Исправлена ​​работа с clojure 1.6.0, leiningen 2.5.0 и исполняемым двоичным файлом. github.com/janpalencar/clojure-parallel-dirsize - person jppalencar; 22.08.2015