2014-04-10 64 views
0

下面的代碼運行用戶和寫入文件的比較。我已經刪除了一些代碼,使其儘可能簡明,但速度是一個問題,也是在這個代碼:使用參數圖提高性能

import scala.collection.JavaConversions._ 

object writedata { 

    def getDistance(str1: String, str2: String) = { 

    val zipped = str1.zip(str2) 
    val numberOfEqualSequences = zipped.count(_ == ('1', '1')) * 2 

    val p = zipped.count(_ == ('1', '1')).toFloat * 2 
    val q = zipped.count(_ == ('1', '0')).toFloat * 2 
    val r = zipped.count(_ == ('0', '1')).toFloat * 2 
    val s = zipped.count(_ == ('0', '0')).toFloat * 2 

    (q + r)/(p + q + r) 

    }            //> getDistance: (str1: String, str2: String)Float 

    case class UserObj(id: String, nCoordinate: String) 
    val userList = new java.util.ArrayList[UserObj] //> userList : java.util.ArrayList[writedata.UserObj] = [] 
    for (a <- 1 to 100) { 
    userList.add(new UserObj("2", "101010")) 
    } 
    def using[A <: { def close(): Unit }, B](param: A)(f: A => B): B = 
    try { f(param) } finally { param.close() } //> using: [A <: AnyRef{def close(): Unit}, B](param: A)(f: A => B)B 

    def appendToFile(fileName: String, textData: String) = 
    using(new java.io.FileWriter(fileName, true)) { 
     fileWriter => 
     using(new java.io.PrintWriter(fileWriter)) { 
      printWriter => printWriter.println(textData) 
     } 
    }            //> appendToFile: (fileName: String, textData: String)Unit 

    var counter = 0;        //> counter : Int = 0 

    for (xUser <- userList.par) { 
    userList.par.map(yUser => { 
     if (!xUser.id.isEmpty && !yUser.id.isEmpty) 
     synchronized { 
      appendToFile("c:\\data-files\\test.txt", getDistance(xUser.nCoordinate , yUser.nCoordinate).toString) 
     } 
    }) 
    } 

} 

上面的代碼以前是勢在必行的解決方案,所以.PAR功能是內內和外循環。我試圖將其轉換爲更實用的實現,同時也利用了Scala的並行集合框架。

在這個例子中,數據集的大小是10,但在代碼im工作在 大小是8000轉換爲64'000'000比較。我是 使用一個同步塊,以便多個線程不寫入 同一個文件在同一時間。甲性能改良效果IM考慮 被填充內環內的單獨集合(userList.par.map(yUser => {) ,然後寫該集合出單獨的文件中。

是否有其他的方法,我可以使用改善性能,以便我可以 處理包含8000個項目的列表,而不是上面的100個示例?

+0

1.您看起來像'appendToFile'方法每次寫入文件時打開並關閉文件寫入器。 嘗試在處理的開始處打開文件並在最後關閉它。另外,儘量不要阻止'par'處理的線程。使用ArrayBlockingQueue並從另一個執行上下文寫入文件。使用AtomicInt或AtomicLong作爲計數器 –

+0

也建議使用StringBuffer(因爲它是線程安全的),並定期將其刷新到PrintWriter –

回答

1

我不確定您是否刪除了太多的代碼以便清晰,但從我所能看到的,沒有什麼可以並行運行的,因爲你正在做的唯一的事情是寫入文件。

編輯:

你應該做的一件事是在對appendToFile的同步調用之前移動getDistance(...)計算,否則你的並行化代碼最終會成爲順序的。

而不是調用同步的appendToFile,我會以非同步的方式調用appendToFile,但每次調用該方法都會將新行添加到某個同步隊列中。然後我會有另一個線程定期將該隊列刷新到磁盤。但是,您還需要添加一些內容,以確保在完成所有計算後隊列也被刷新。所以這可能會變得複雜......

另外,你也可以保留你的代碼,並簡單地放棄對appendToFile調用的同步。這似乎是println itself is synchronized。但是,這將是有風險的,因爲println沒有正式同步,並且在未來版本中可能會更改。

+0

請參閱問題更新 –