Scala 中的孤儿期货

Orphan Futures in Scala

是否有一种惯用的方法来处理副作用 scala.concurrent.Future 其结果在调用者中并不是真正需要的(即计算调用方法的 return 值不需要成功或失败)?例如,

object XYZ {
  def log(s: String): Future[Unit] = ???
}

在没有任何回调的情况下简单地调用 XYZ.log("xyz") 并继续执行真正重要的任务是否正确?这个孤儿 Future 不会被认为是代码味道吗?它有机会在执行前被垃圾回收吗?

Won't this orphan Future be considered code smell?

不超过任何其他丢弃的非Unit值。请注意,有些人 do consider any discarded value to be a code smell, which is why -Ywarn-value-discard and NonUnitStatements wart 存在。

Any chance for it to be garbage collected before it is executed?

Future 对象本身可能会被垃圾回收,但它会将任务提交给线程池,而线程池不会(因为池中包含对任务的引用)。除了

这样的情况
def log(s: String): Future[Unit] = Future.just(())

当然。

当我们有这样的 Future 时,它们不是主要业务逻辑的一部分,而是因为它们的副作用而执行,也就是说,代表一个单独的关注点,例如日志记录,然后考虑 运行 它们一个单独的专用执行上下文。例如,创建一个单独的池

val numOfThreads = 2
val threadPoolForSeparateConcerns = Executors.newFixedThreadPool(numOfThreads, (r: Runnable) => new Thread(r, s"thread-pool-for-separate-concerns-thread-${Random.nextInt(numOfThreads)}"))
val separateConcernsEc = ExecutionContext.fromExecutor(threadPoolForSeparateConcerns)

然后确保在 运行 单独关注点

时传递它
object XYZ {
  def log(s: String, ec: ExecutionContext): Future[Unit] = ???
}

XYZ.log("Failed to calculate 42", separateConcernsEc)

通过将主要业务逻辑线程池与副线程池分开,我们可以最大限度地减少因资源匮乏等问题而破坏主要业务逻辑的可能性。