В чем разница между выходом следующих параллельных программ Scala - PullRequest
0 голосов
/ 29 апреля 2019
// First
import concurrent.Future
import concurrent.ExecutionContext.Implicits.global
for {
  _ <- Future { Thread.sleep(3000); println("a") }
  _ <- Future { Thread.sleep(2000); println("b") }
  _ <- Future { Thread.sleep(1000); println("c") }
} {}


// Second

import concurrent.Future
import concurrent.ExecutionContext.Implicits.global
val future1 = Future { Thread.sleep(3000); println("a") }
val future2 = Future { Thread.sleep(2000); println("b") }
val future3 = Future { Thread.sleep(1000); println("c") }
for {
  _ <- future1
  _ <- future2
  _ <- future3
} {}


Ответы [ 2 ]

4 голосов
/ 29 апреля 2019

Вы можете использовать команду ниже, чтобы лучше понять, что делает компилятор Scala под капотом:

$ scalac -Xprint:typer MainClass.scala

«Первый» будет переведен в:


    scala.concurrent.Future.apply[Unit]({
      java.lang.Thread.sleep(3000L); scala.Predef.println("a")
    })(scala.concurrent.ExecutionContext.Implicits.global)
      .foreach[Unit](((_: Unit) =>
      scala.concurrent.Future.apply[Unit]({
        java.lang.Thread.sleep(2000L); scala.Predef.println("b")
      })(scala.concurrent.ExecutionContext.Implicits.global)
        .foreach[Unit](((_: Unit) => scala.concurrent.Future.apply[Unit]({
        java.lang.Thread.sleep(1000L); scala.Predef.println("c")
      })(scala.concurrent.ExecutionContext.Implicits.global)
        .foreach[Unit](((_: Unit) => ()))(scala.concurrent.ExecutionContext.Implicits.global)))(scala.concurrent.ExecutionContext.Implicits.global)))
    (scala.concurrent.ExecutionContext.Implicits.global);

«Второй» в

    val future1: scala.concurrent.Future[Unit] = scala.concurrent.Future.apply[Unit]({
      java.lang.Thread.sleep(3000L);
      scala.Predef.println("a")
    })(scala.concurrent.ExecutionContext.Implicits.global);
    val future2: scala.concurrent.Future[Unit] = scala.concurrent.Future.apply[Unit]({
      java.lang.Thread.sleep(2000L);
      scala.Predef.println("b")
    })(scala.concurrent.ExecutionContext.Implicits.global);
    val future3: scala.concurrent.Future[Unit] = scala.concurrent.Future.apply[Unit]({
      java.lang.Thread.sleep(1000L);
      scala.Predef.println("c")
    })(scala.concurrent.ExecutionContext.Implicits.global);
    {
      future1.flatMap[Unit](((_: Unit) => future2.flatMap[Unit](((_: Unit) => future3.map[Unit](((_: Unit) => ()))(scala.concurrent.ExecutionContext.Implicits.global)))(scala.concurrent.ExecutionContext.Implicits.global)))(scala.concurrent.ExecutionContext.Implicits.global);
      ()
    }

В случае «Первого» следующее Будущее будет создано внутри «.foreach» первого Будущего и т. Д.

Во втором случае сначала будут созданы все 3 фьючерса, выполненные параллельно, а затем в виде flatMap.

1 голос
/ 29 апреля 2019

Поскольку выражение for равно desugared для серии вложенных вызовов flatMap / map, экземпляры Future в первых примерах будут выполняться последовательно.

В то время как код во втором примере будет, в зависимости от области действия ExecutionContext, запускать экземпляры Future параллельно.

Еще одна вещь, о которой следует помнить, это то, что Scala Futuresстрогий, что означает, что вы не можете отделить определение Future от его выполнения.Вы можете прочитать об этой и других Future слабостях здесь:

Scala Futures vs Monix Tasks

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...