【问题标题】:Computing folder size计算文件夹大小
【发布时间】:2011-08-17 19:23:42
【问题描述】:

我正在尝试并行计算文件夹大小。 也许这是天真的方法。 我所做的是,我将每个分支节点(目录)的计算交给代理。 所有叶节点的文件大小都添加到 my-size。 好吧,它不起作用。 :)

'scan' 工作正常,串行。 '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))))))

你有什么想法,我做错了什么?

谢谢。

【问题讨论】:

    标签: clojure agent


    【解决方案1】:

    无需使用原子保持状态。纯函数:

    (defn psize [f]
      (if (.isDirectory f)
        (apply + (pmap psize (.listFiles f)))
        (.length f)))
    

    【讨论】:

    • 新手在做 lisp/clojure 时是一种永久的心态;)谢谢。
    • ürgenHötzel 嗯,这有点鼓舞人心。但是当您阅读 clojure/docs 时,您会发现 'pmap' 是 "...仅对 f 的时间支配协调开销的计算密集型函数有用。" 计算文件夹大小的解决方案,来自我的观点更多的是生产者/消费者问题。当生产者将根目录分割成分支节点,消费者从这些分支中计算文件大小时。它更多的是设置正确的问题块大小。我受到另一个 post 的启发
    【解决方案2】:

    那么并行计算文件大小应该这么简单吗?

    这不是:)

    我试图更好地解决这个问题。我意识到我正在执行阻塞 I/O 操作,因此 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)
    

    如果您发现任何错误/错误,欢迎您分享您的想法!

    【讨论】:

    猜你喜欢
    • 2011-01-12
    • 1970-01-01
    • 2019-01-06
    • 2022-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多