2014-06-18 62 views
-3

我有地圖的矢量,像下面雖然有高達每個數據集possbly 100個地圖:總和串值

data({ a:a b:"2" c:t}{ a:b b:"0" c:t}{ a:c b:"-4" c:t}{ a:d b:"100" c:t}{ a:e b:"50" c:t}) 

我需要產生的總和:乙

values(map :b data) 
sum(reduce + (map read-string values) 

這給出了所需的結果,但計算時間很長,大約爲1/10秒。我正在爲數十萬個數據集執行此操作,因此它會佔用大量的處理時間來執行此操作。

任何人都可以提出一個更有效率/更快的方法來這種方法?

感謝

+8

請給真正的clojure代碼而不是這個pseude代碼。我們可以接受。 – ivant

+0

這是真正的clojure代碼... – redhands

+0

爲什麼不將int存儲爲int而不是字符串?性能不僅來自算法,它是結構+算法的組合 – Ankur

回答

3

一種可能性是使用並行運行reducers

(require '[clojure.core.reducers :as r]) 
(r/reduce + (r/map read-string values)) 

對於你的小型測試用例,這不會改善運行時間,但對於大型數據集,它應該。

+0

願意使用reducer,但不幸的是我使用的是clojure的舊版本,並且無法馬上升級 – redhands

+3

您可以使用'pmap'獲得一些並行性。它可以從clojure 1.0獲得,所以你應該可以使用它。 – ivant

3

您可以嘗試使用Integer/parseIntLong/parseLong,而不是更普遍read-string

[編輯]

使用Clojure 1.5.1一個簡單的測試表明,parseInt函數是快約10倍:

user=> (time (dotimes [n 100000] (read-string "10"))) 
"Elapsed time: 142.516849 msecs" 
nil 

user=> (time (dotimes [n 100000] (Integer/parseInt "10"))) 
"Elapsed time: 12.754187 msecs" 
nil 
+0

我曾試過(reduce +(map#(Integer/parseint%1)values))但它沒有區別 – redhands

5

在Clojure 1.2.1中,這是您的總100,000個數據集場景的1/10中略微超過1/10秒的情況。它基本上是你的代碼(這不是真正有效的clojure語法,但我們得到了要點),但以某種方式快速運行10.000倍。

;generate 10.000 datasets of 100 maps having 10 fields each 

(def scenario-data 
    (vec (repeatedly 10000 
        (fn [] (vec (repeatedly 100 (fn [] (zipmap 
                  [:a :b :c :d :e :f :g :h :i :j] 
                  (repeatedly (fn [] (str (- (rand-int 2000) 1000)))))))))))) 


;now map the datasets into the reduced sums of the parsed :b fields of each dataset 

(time (doall (map (fn [dataset] (reduce (fn [acc mp] (+ acc (Integer/parseInt (:b mp)))) 0 dataset)) 
        scenario-data))) 
"Elapsed time: 120.43267 msecs" 
=> (2248 -6383 7890 ...) 

由於這種情況是非常內存密集型(10.000的數據集〜= 600MB,總計算使用〜4GB),我不是我家的機器上運行100.000數據集的場景。不過,我可以運行它,如果我不保存在內存中的數據集,但映射了一隻懶惰的序列,而不堅持着它的頭..

(time (doall (map (fn [dataset] (reduce (fn [acc mp] (+ acc (Integer/parseInt (:b mp)))) 0 dataset)) 
        (repeatedly 100000 
           (fn [] (repeatedly 100 (fn [] (zipmap 
                   [:a :b :c :d :e :f :g :h :i :j] 
                   (repeatedly (fn [] (str (- (rand-int 2000) 1000)))))))))))) 
"Elapsed time: 30242.371308 msecs" 
=> (-4975 -843 1560 ...) 

這30秒計算你100.000數據集的版本,並包括生成數據所需的所有時間。使用pmap的時間大約減半(4個核心)。

編輯:在具有足夠內存的機器上創建完全實現的100.000數據集需要135秒。運行總和代碼需要約1500毫秒。使用pmap將其削減至約750毫秒。一個read-string版本是〜3.5倍慢。

TL/DR:您發佈的算法可以在1秒內在100.000數據集情形下運行,並提供足夠的內存。

請發佈您的完整代碼,包括您如何閱讀數據集並將其保存在內存中,並確保這次的語法和觀察結果都準確無誤。它可能更多是因爲沒有從源頭上懶散地讀取數據集而導致的內存問題。