Две вещи:
Не всегда гарантируется, что параллельные операции всегда будут быстрее. Если ваша последовательная операция коротка, то накладные расходы от отправки в несколько потоков и последующего сбора всех результатов могут быть больше, чем ускорение.
Посмотрите, что вы измеряете. У вас есть одна последовательная операция, которая выполняет X объема работы, или 3 операции, которые выполняют X / 3 объема работы. Вы измеряете их все, а затем сравниваете: время выполнения X последовательно с общим временем выполнения X / 3 объема работы в 3 задачах. Если последовательный запуск занимал около 3 секунд, а каждый параллельный запуск занимал около 1 секунды, то logi c обе версии занимают 3 секунды. Что может быть правдой, если мы измеряем время использования ЦП, но не совсем, если мы измеряем время от начала всей этой работы до конца sh.
Если я запустил ваш код, я получу
@ ParallelMap.main(Array[String]())
List((Serial,Result(30,12.058612958004232)), (Parallel,Result(30,12.005087116995128)))
Однако, если я запустил этот код вместо:
object ParallelMap extends IOApp {
def slowAdd(nums: Seq[Int]): Int = nums.foldLeft(0) {
(out: Int, next: Int) =>
val seconds: TimeUnit = java.util.concurrent.TimeUnit.SECONDS
val delay: IO[Unit] = IO.sleep(FiniteDuration(1L, seconds))
delay.unsafeRunSync()
out + next
}
def timeIO[A](op: IO[A]): IO[Result[A]] = for {
start <- IO(System.nanoTime / 1e9)
out <- op
stop = System.nanoTime / 1e9
} yield Result(out, stop - start)
def addInSequence(first: Seq[Int], second: Seq[Int], third: Seq[Int]): IO[Result[Int]] = {
timeIO(IO(List(first, second, third).map(ns => slowAdd(ns)).sum))
}
def addInParallel(first: Seq[Int], second: Seq[Int], third: Seq[Int]): IO[Result[Int]] = {
// I changed is as little as possible so that you would still see
// similarity to your code, but normally I would write
// .parTraverse(f) instead of .map(f).parSequence
timeIO(List(first, second, third).map(ns => IO(slowAdd(ns))).parSequence.map(_.sum))
}
def run(args: List[String]): IO[ExitCode] = {
val nums: Seq[Int] = 1 to 4
val results: IO[Seq[(String, Result[Int])]] = for {
serial <- addInSequence(nums, nums, nums)
parallel <- addInParallel(nums, nums, nums)
} yield Seq(("Serial", serial), ("Parallel", parallel))
val report: IO[Unit] = results.map(println)
report.unsafeRunSync()
IO(ExitCode.Success)
}
}
, чтобы измерить то, что, как мне кажется, вы хотели измерить, я получаю следующий результат:
@ ParallelMap.main(Array[String]())
List((Serial,Result(30,12.006349742005114)), (Parallel,Result(30,4.003020468982868)))
который показывает, что параллельные вычисления были в 3 раза быстрее, чем последовательные.