Tamaño de la carpeta de computación
Pregunta
Estoy tratando de calcular el tamaño de la carpeta en paralelo. Quizás sea un enfoque ingenuo. Lo que hago es que doy cálculo de cada nodo de rama (directorio) a un agente. Todos los nodos de hoja tienen sus tamaños de archivo agregados a mi tamaño. Bueno, no funciona. :)
'Scan' funciona bien, en serie. 'PSCAN' imprime solo archivos desde el primer nivel.
(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))))))
¿Tienes alguna idea, qué he hecho mal?
Gracias.
Solución 2
Entonces, ¿contar los archivos en paralelo debería ser tan fácil?
No es :)
Traté de resolver este problema mejor. Me di cuenta de que estoy haciendo Bloqueo de operaciones de E/S Entonces PMAP no hace el trabajo. Estaba pensando tal vez dando trozos de directorios (sucursales) a los agentes para procesarlo de forma independiente tendría sentido. Parece que lo hace :) Bueno, todavía no lo he comparado.
Funciona, pero puede haber algunos problemas con enlaces simbólicos en sistemas similares a 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*)))))
Puedes iniciarlo escribiendo
(producer (list user-dir))
(consumer)
Para el tipo de resultado
@size-total
Puedes detenerlo (hay futuros en ejecución, corrígeme si me equivoco)
(swap! run? not)
Si encuentra algún error/error, ¡puede compartir sus ideas!
Otros consejos
No es necesario mantener el estado usando átomos. Puro funcional:
(defn psize [f]
(if (.isDirectory f)
(apply + (pmap psize (.listFiles f)))
(.length f)))