Как проверить, работают ли фьючерсы последовательно в Scala? - PullRequest
0 голосов
/ 17 апреля 2020

Предположим, у меня есть следующие методы:

def callApis(f1, f2, f3):Future[Result] {
    for {
        a <- Future { f1 }
        b <- Future { f2 }
        c <- Future { f3 }
    } yield Result(a,b,c)
}

Если вы знакомы с scala, вы будете знать, что строки в блоке for будут выполняться последовательно. Более конкретно c, а будет рассчитываться первым. Затем, когда у нас будет результат для a, код будет вычислять b. Затем, когда у нас будет результат для b, код будет вычислять c.

Мой вопрос: как написать тест UNIT, который гарантирует, что всегда вычисляется a перед вычислением b, и b всегда вычислять перед вычислением c? Я боюсь, что кто-то мало знает о том, как работает фьючерс в scala. Они могут случайно заставить этот код работать асинхронно.

Я имею в виду, что люди могут случайно сделать что-то подобное, это заставляет a, b, c вычисляться асинхронно (что Я не хочу, чтобы люди это делали) :

def callApis(f1, f2, f3):Future[Result] {
    val fut1 = Future { f1 }
    val fut2 = Future { f2 }
    val fut3 = Future { f3 }

    for {
        a <- fut1
        b <- fut2
        c <- fut3
    } yield Result(a,b,c)
}

1 Ответ

0 голосов
/ 17 апреля 2020

Возможно, попробуйте определить однопоточный контекст выполнения и указать его в блоках, которые должны выполняться последовательно. Например,

trait SerialExecutionContext extends ExecutionContext {
  val singleThreadPool = Executors.newFixedThreadPool(1, (r: Runnable) => new Thread(r, s"single-thread-pool"))
  val serialEc = ExecutionContext.fromExecutor(singleThreadPool)
  override def execute(runnable: Runnable): Unit = serialEc.execute(runnable)
  override def reportFailure(cause: Throwable): Unit = serialEc.reportFailure(cause)
}


def callApis()(implicit ec: SerialExecutionContext): Future[Result] = {
  val fut1 = Future { ...doSomething... }
  val fut2 = Future { ...doSomething... }
  val fut3 = Future { ...doSomething... }

  for {
    a <- fut1
    b <- fut2
    c <- fut3
  } yield Result(a,b,c)
}

Теперь callApis может оценить, только если мы можем доказать, что во время компиляции существует контекст последовательного выполнения. Поскольку внутри тела у нас есть только один доступный поток, фьючерсы вынуждены запускаться только после завершения предыдущего.

...