使用“时间”测量Clojure的将来内部执行的流程的时间

时间:2018-06-26 14:12:57

标签: clojure benchmarking future

下面是我正在处理的应用程序的简化版本。具体来说,我对基准process-list的执行时间感兴趣。在函数process-list中,我将输入列表划分为多个分区,这些分区等于我要并行执行的线程数。然后,我通过调用future将每个分区传递给线程。最后,在main中,我将process-list包裹在time周围。时间应该返回由process-list完成的处理时间,但显然,它仅返回创建将来线程所花费的时间,而不必等待将来执行完成。如何在process-list内取消对期货的引用,以确保所用的时间占期货线程执行完成的时间?

(ns listProcessing
  (:require [clojure.string]
            [clojure.pprint]
            [input-random :as input]))

  (def N-THREADS 4)      
  (def element_processing_retries (atom 0))

  (def list-collection
     "Each element is made into a ref"
     (map ref input/myList))

  (defn partition-list  [threads list]
      "partition list into required number of partitions which is equal 
      to the number of threads"
      (let [partitions (partition-all 
         (Math/ceil (/ (count list) threads))  list)]
            partitions))
 (defn increase-element [element]
     (ref-set element inc))

 (defn process-list [list]
      "Process `members of list` one by one."
      (let [sub-lists (partition-list N-THREADS list)]
      (doseq [sub-list sub-lists]
        (let [futures '()
              myFuture        (future (dosync  (swap! element_processing_retries inc)
              (map increase-element sub-list)))]
              (cons myFuture futures) 
              (map deref futures))))) 


  (defn main []      
       (let [f1 (future (time (process-list input/mylist)))]        
        @f1)       
  (main)    
  (shutdown-agents)

下面是简化列表输入的一个示例:请注意,此处的输入是简化的,列表处理也可以简化问题。

(ns input-random)
(def myList (list 1 2 4 7 89 12 34 45 56))

1 个答案:

答案 0 :(得分:1)

这会有一些开销。如果您尝试的是time毫秒差异,则可能会有些偏差(尽管分钟的时间绝对不应该使用time)。

我认为您的示例有些复杂,因此我将其简化为我认为代表问题的示例:

(time (doseq [n (range 5)]
        (future
          (Thread/sleep 2000))))

"Elapsed time: 1.687702 msecs"

这里的问题与您的代码中的问题相同:真正要做的只是时间doseq分配所有作业所花费的时间。

我的想法是将每个完成的任务放到一个原子中,然后在繁忙的等待中检查结束条件:

(defn do-stuff [n-things]
  (let [ret-atom (atom 0)]
    (doseq [n (range n-things)]
      (future
        (Thread/sleep 2000)
        (swap! ret-atom inc)))

    ret-atom))

; Time how long it takes the entire `let` to run
(time
  (let [n 5
        ret-atom (do-stuff n)]

    ; Will block until the condition is met
    (while (< @ret-atom n))))

"Elapsed time: 2002.813288 msecs"

您很难做的原因就是您正在doseq中产生一些副作用。没有什么定义“完成”是什么,因此没有什么可以阻止的。我对core.async不太满意,但我怀疑其中可能会有帮助。可能会阻塞对<!!的调用,直到某个通道具有一定数量的元素为止。在这种情况下,您只需要在结果生成时将其放入渠道即可。