ConcurrentHashMap с функциональным программированием.Безопасно ли приостановить небезопасный запуск? - PullRequest
0 голосов
/ 02 марта 2019

Вопрос: Безопасно ли приостановить unsafeRunSync с IO?Например,

val io: IO[Unit] = //...
val io2: IO[Unit] = IO(io.unsafeRunSync)

Причина, по которой я бы сделал это, заключается в том, что у меня есть некоторый класс, параметризованный с помощью F[_]: Effect, который похож на кеш:

import cats.effect.Effect

final class MyChache[F[_]](implicit F: Effect[F]) {
  private val cache = new ConcurrentHashMap[Int, String]

  def getOrCreate(key: Int): F[String] = F delay {
    cache.computeIfAbsent(
      key, 
      k => longRunningEffecfulComputation(k).toIO.unsafeRunSync() // <-- Here
    )
  }
}


object MyCache {
  def longRunningEffecfulComputation[F[_] : Effect](key: Int): F[String] = {
    //...
  }
}

Суть в том, что я хочу запустить этодлительный эффект, полный расчет только один раз для каждого ключа (это довольно редко).Тем не менее, я хотел бы остаться неблокирующим при получении существующего ключа.

ConcurrentHashMap кажется идеальным выбором, но он требует этого уродливого трюка с запуском и приостановкой эффекта.Есть ли лучший путь?

1 Ответ

0 голосов
/ 03 марта 2019

Это, по крайней мере, потенциально небезопасно.Предположим, что при длительных вычислениях использовался пул потоков фиксированного размера:

import java.util.concurrent.Executors
import scala.concurrent.ExecutionContext
import cats.effect.Async

object MyCache {
  val smallThreadPool = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(1))

  def longRunningEffectfulComputation[F[_] : Effect](key: Int): F[String] = {
    Effect[F].flatMap(Async.shift[F](smallThreadPool))(_ => Effect[F].delay("test"))
  }
}

А кэш-память использовалась в том же пуле потоков:

val io = for {
  _ <- IO.shift(MyCache.smallThreadPool)
  x <- new MyCache[IO].getOrCreate(1)
} yield x

Когда вы вызываете io.unsafeRunSync(),вы увидите, что он не завершается.

Вместо этого вы можете использовать API-интерфейс кэша, поддерживающий эффект кошки, например ScalaCache .

...