使用ScalaMeter测试并行操作的性能



我使用了取自ScalaMeter示例存储库的basic示例(https://github.com/scalameter/scalameter-examples)。示例的代码如下:

measure method "map" in {
  using(ranges) in { r =>
    r.map(_ + 1)
  }
}

在我的情况下,我想测试并行运行一些操作的加速率。一个简单的例子可以是,我划分了一个必须映射的范围。我使用Java8中的ExecutorService并行运行这些任务。它看起来像这样:

val cores = Runtime.getRuntime.availableProcessors()
val pool = Executors.newFixedThreadPool(cores)
measure method "parallel map" in {
  using(ranges) in { r =>
    val tasks = (0 until cores).map { t =>
      new Callable[Unit] {
        override def call() = (0 + t until r.last by cores).map(_ + 1)
      }
    }
    import collection.JavaConverters._
    pool.invokeAll(tasks.asJava)
  }
}

问题是,尽管并行测试完成(您可以看到时间结果),但它不会返回退出代码。这意味着,如果我将Bench.LocalTime更改为Bench.ForkedTime,即使结果也会消失。我很困惑发生了什么事。有什么想法吗?

好吧,这很琐碎,因为我忘记了shutdown()池。在invokeAll之后添加它之后,我得到如下结果:

measure method "parallel map" in {
  using(ranges) in { r =>
    val pool = Executors.newFixedThreadPool(cores)
    val tasks = (0 until cores).map { t =>
      new Callable[Unit] {
        override def call() = (0 + t until r.last by cores).map(_ + 1)
      }
    }
    pool.invokeAll(tasks.asJava)
    pool.shutdown()
  }
}

唯一的问题是,现在,不仅要测量动作,还要测量ExecutorService的创建时间并关闭它。但我想这暂时不会改变结果。


事实上,经过一段时间后,我发现了一种更简单、更"Scala"的方法来完成上述操作。您可以简单地创建一个任务列表作为要生成的函数列表(或者仍然可以是Callables的列表),然后使用parallel集合调用所有任务。代码如下:

measure method "parallel map" in {
  using(ranges) in { r =>
    val tasks =  (0 until cores).flatMap { t =>
        (0 + t until r by cores).map(i => () => i+1)
    }
    tasks.par.map(_.apply())
  }
}

或者更容易,因为任务列表现在不关心cores

val tasks = (0 until r).map(i => () => i+1)

相关内容

  • 没有找到相关文章

最新更新