ЗИО: Как рассчитать только один раз?
Я использую ZIO: https://github.com/zio/zio
в моем build.sbt
:
"dev.zio" %% "zio" % "1.0.0-RC9"
Независимо от того, что я пробовал, мои результаты всегда вычисляются каждый раз, когда они мне нужны:
val t = Task {
println(s"Compute")
12
}
val r = unsafeRun(for {
tt1 <- t
tt2 <- t
} yield {
tt1 + tt2
})
println(r)
Для этого примера журнал выглядит так:
Compute
Compute
24
Я пробовал с Promise
:
val p = for {
p <- Promise.make[Nothing, Int]
_ <- p.succeed {
println(s"Compute - P")
48
}
r <- p.await
} yield {
r
}
val r = unsafeRun(for {
tt1 <- p
tt2 <- p
} yield {
tt1 + tt2
})
И я получаю ту же проблему:
Compute - P
Compute - P
96
Я пробовал с
val p = for {
p <- Promise.make[Nothing, Int]
_ <- p.succeed(48)
r <- p.await
} yield {
println(s"Compute - P")
r
}
Сначала я подумал, что, возможно, конвейер выполняется, но не пересчитывается значение, но я тоже не работаю.
Я хотел бы иметь возможность асинхронно вычислять мои значения и иметь возможность их повторного использования. Я посмотрел на Как сделать Scalaz ZIO ленивым? но у меня это тоже не работает.
2 ответа
У ZIO есть памятка, которая должна делать то, что вы хотите. У меня нет способа проверить это только сейчас, но это должно работать примерно так:
for {
memoized <- t.memoize
tt1 <- memoized
tt2 <- memoized
} yield tt1 + tt2
Обратите внимание, что если вторая и третья строки вашего реального кода не имеют разветвления, которое может привести к Task
никогда не вызывается или не вызывается только один раз, это дает тот же ответ и побочные эффекты, что и гораздо проще:
t flatMap {tt => tt + tt}
Есть ли у результатов вычисления побочные эффекты? Если это не так, вы можете просто использовать обычный старый ленивый вал, возможно, поднял в ZIO
,
lazy val results = computeResults()
val resultsIO = ZIO.succeedLazy(results)
Если у него есть побочные эффекты, вы не сможете на самом деле кэшировать результаты, потому что они не будут ссылочно прозрачными, а в этом весь смысл ZIO
, Что вам, вероятно, придется сделать, это flatMap
на вашем компьютере Task
и написать остальную часть вашей программы, которая нуждается в результате этого вычисления внутри этого вызова flatMap
, пронизывающий result
Значение в качестве параметра через ваши вызовы функций, где это необходимо.
val compute = Task {
println(s"Compute")
12
}
compute.flatMap { result =>
// the rest of your program
}