Я новичок в Scala, и я практикуюсь в библиотеке Futures, создав несколько схем повторов.При этом я получил следующий фрагмент кода:
import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
object Retries extends App {
var retries = 0
def resetRetries(): Unit = retries = 0
def calc() = if (retries > 3) 10 else {
retries += 1
println(s"I am thread ${Thread.currentThread().getId} This is going to fail. Retry count $retries")
throw new IllegalArgumentException("This failed")
}
def fCalc(): Future[Int] = Future(calc())
resetRetries()
val ff = fCalc() // 0 - should fail
.fallbackTo(fCalc()) // 1 - should fail
.fallbackTo(fCalc()) // 2 - should fail
.fallbackTo(fCalc()) // 3 - should fail
.fallbackTo(fCalc()) // 4 - should be a success
Await.ready(ff, 10.second)
println(ff.isCompleted)
println(ff.value)
}
Каждый раз, когда я запускаю этот код, я получаю разные результаты.Вот примеры результатов, которые я получаю:
Выход 1
I am thread 12 This is going to fail. Retry count 1
I am thread 14 This is going to fail. Retry count 3
I am thread 13 This is going to fail. Retry count 2
I am thread 11 This is going to fail. Retry count 1
I am thread 12 This is going to fail. Retry count 4
true
Some(Failure(java.lang.IllegalArgumentException: This failed))
Выход 2
I am thread 12 This is going to fail. Retry count 2
I am thread 11 This is going to fail. Retry count 1
I am thread 13 This is going to fail. Retry count 3
I am thread 14 This is going to fail. Retry count 4
true
Some(Success(10))
Выход 3
I am thread 12 This is going to fail. Retry count 1
I am thread 11 This is going to fail. Retry count 1
I am thread 12 This is going to fail. Retry count 2
I am thread 12 This is going to fail. Retry count 3
I am thread 12 This is going to fail. Retry count 4
true
Some(Failure(java.lang.IllegalArgumentException: This failed))
Этоне всегда бывает, что результаты будут чередоваться между успехом и неудачей.Может быть больше, чем пара неудачных запусков, пока не появится успешный.
Насколько я понимаю, должно быть только 4 журнала "Я - нить х Это не удастся. Количество повторов х" и этидолжно быть следующее:
I am thread a This is going to fail. Retry count 1
I am thread b This is going to fail. Retry count 2
I am thread c This is going to fail. Retry count 3
I am thread d This is going to fail. Retry count 4
Не обязательно в этом порядке - поскольку я не знаю, как именно работает модель потоков Scala - но вы меня поняли.Тем не менее, я получаю этот недетерминированный вывод, с которым я не могу справиться. Итак ... мой вопрос: откуда берется этот недетерминированный вывод?
Я хотел бы отметить, что следующий механизм повторения дает последовательноте же результаты:
import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
object Retries extends App {
var retries = 0
def resetRetries(): Unit = retries = 0
def calc() = if (retries > 3) 10 else {
retries += 1
println(s"I am thread ${Thread.currentThread().getId} This is going to fail. Retry count $retries")
throw new IllegalArgumentException("This failed")
}
def retry[T](op: => T)(retries: Int): Future[T] = Future(op) recoverWith { case _ if retries > 0 => retry(op)(retries - 1) }
resetRetries()
val retriableFuture: Future[Future[Int]] = retry(calc())(5)
Await.ready(retriableFuture, 10 second)
println(retriableFuture.isCompleted)
println(retriableFuture.value)
}
Вывод
I am thread 11 This is going to fail. Retry count 1
I am thread 12 This is going to fail. Retry count 2
I am thread 11 This is going to fail. Retry count 3
I am thread 12 This is going to fail. Retry count 4
true
Some(Success(10))
В то время как если я уменьшу количество повторных попыток (retry(calc())(3)
), результатом будет неудачное будущее, как и ожидалось
I am thread 11 This is going to fail. Retry count 1
I am thread 12 This is going to fail. Retry count 2
I am thread 11 This is going to fail. Retry count 3
I am thread 12 This is going to fail. Retry count 4
true
Some(Failure(java.lang.IllegalArgumentException: This failed))