Scala如何减少执行时间

时间:2018-04-09 17:38:21

标签: scala

我有一种生成UUID的方法和代码如下:

functions

我将其称为如下:

def generate(number : Int): List[String] = {
List.fill(number)(Generators.randomBasedGenerator().generate().toString.replaceAll("-",""))
}

但是为了运行上面的for(i <-0 to 100) { val a = generate(1000000) println(a) } 循环,执行需要大约8-9分钟,还有其他方法可以最小化执行时间吗?

注意:为了便于理解,我添加了for循环,但在实际情况下,for方法会同时从其他请求调用数千次。

3 个答案:

答案 0 :(得分:2)

问题是List。使用1,000,000个生成和处理的元素填充List将需要时间(和内存),因为必须实现这些元素中的每一个。

如果您不需要实现它们,则可以立即生成无限数量的已处理UUID字符串,直到实际需要它们为止。

def genUUID :Stream[String] = Stream.continually {
  Generators.randomBasedGenerator().generate().toString.filterNot(_ == '-')
}

val next5 = genUUID.take(5) //only the 1st (head) is materialized
next5.length                //now all 5 are materialized

您可以使用StreamIterator进行无限收集,无论哪种情况对您的工作流程最有利(或最不烦人)。

答案 1 :(得分:1)

您可以使用scala的并行集合来分割多个核心/线程上的负载。

您还可以避免每次都创建新的生成器:

class Generator {
  val gen = Generators.randomBasedGenerator()
  def generate(number : Int): List[String] = {
    List.fill(number)(gen.generate().toString.replaceAll("-",""))
  }
}

答案 2 :(得分:1)

基本上你没有使用最快的实现。将Random传递给构造函数Generators.randomBasedGenerator(new Random(System.currentTimeMillis()))时应该使用那个。我做了下一件事:

  • 使用Array而不是List(数组更快)
  • 删除字符串替换,让我们测量生成的纯粹性能

依赖关系:"com.fasterxml.uuid" % "java-uuid-generator" % "3.1.5"

结果:

Generators.randomBasedGenerator(). Per iteration: 1579.6 ms
Generators.randomBasedGenerator() with passing Random Per iteration: 59.2 ms

代码:

import java.util.{Random, UUID}
import com.fasterxml.uuid.impl.RandomBasedGenerator
import com.fasterxml.uuid.{Generators, NoArgGenerator}
import org.scalatest.{FunSuiteLike, Matchers}

import scala.concurrent.duration.Deadline

class GeneratorTest extends FunSuiteLike
  with Matchers {

  val nTimes = 10

  // Let use Array instead of List - Array is faster!
  // and use pure UUID generators
  def generate(uuidGen: NoArgGenerator, number: Int): Seq[UUID] = {
    Array.fill(number)(uuidGen.generate())
  }

  test("Generators.randomBasedGenerator() without passed Random (secure one)") {
    // Slow generator
    val uuidGen = Generators.randomBasedGenerator()
    // Warm up JVM
    benchGeneration(uuidGen, 3)

    val startTime = Deadline.now
    benchGeneration(uuidGen, nTimes)
    val endTime = Deadline.now
    val perItermTimeMs = (endTime - startTime).toMillis / nTimes.toDouble
    println(s"Generators.randomBasedGenerator(). Per iteration: $perItermTimeMs ms")
  }

  test("Generators.randomBasedGenerator() with passing Random (not secure)") {
    // Fast generator
    val uuidGen = Generators.randomBasedGenerator(new Random(System.currentTimeMillis()))
    // Warm up JVM
    benchGeneration(uuidGen, 3)    

    val startTime = Deadline.now
    benchGeneration(uuidGen, nTimes)
    val endTime = Deadline.now
    val perItermTimeMs = (endTime - startTime).toMillis / nTimes.toDouble
    println(s"Generators.randomBasedGenerator() with passing Random Per iteration: $perItermTimeMs ms")
  }

  private def benchGeneration(uuidGen: RandomBasedGenerator, nTimes: Int) = {
    var r: Long = 0
    for (i <- 1 to nTimes) {
      val a = generate(uuidGen, 1000000)
      r += a.length
    }
    println(r)
  }
}