使用par map来提高性能

时间:2014-04-10 20:42:59

标签: performance scala

下面的代码运行用户和写入文件的比较。我删除了一些代码以使其尽可能简洁,但速度也是此代码中的一个问题:

   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,但在我正在处理的代码中 大小为8000,转换为64'000'000比较。我 使用synchronized块,以便多个线程不写入 同时到同一个文件。考虑到性能提升 在内部循环中填充单独的集合(userList.par.map(yUser =&gt; {) 然后将该集合写成单独的文件。

我是否可以使用其他方法来提高性能。这样我就可以 处理一个包含8000个项目而不是上面100个例子的列表?

1 个答案:

答案 0 :(得分:1)

我不确定你是否删除了太多的代码以保持清晰,但从我所看到的,绝对没有什么可以并行运行,因为你唯一要做的就是写一个文件。

编辑:

您应该做的一件事是在同步调用appendToFile之前移动getDistance(...)计算,否则您的并行化代码最终会顺序执行。

我不是调用同步的appendToFile,而是以非同步方式调用appendToFile,但是每次调用该方法都会将新行添加到某个同步队列中。然后我会有另一个线程定期将该队列刷新到磁盘。但是,您还需要添加一些内容以确保在完成所有计算时刷新队列。所以这可能变得复杂......

或者,您也可以保留代码并简单地删除对appendToFile的调用。看来println itself is synchronized。然而,由于println未正式同步,并且未来版本可能会发生变化,因此存在风险。