避免在scala期货中进行不必要的上下文切换



假设我有一个代码执行阻塞/长操作,返回future,然后我需要对结果进行一系列转换。就是一个天真的例子

longOperation().map(_ * 2).map(_.toString).map(_ + "bla").

每个映射都引入了上下文切换。有没有一种简单的方法可以避免上下文切换?我知道蹦床执行上下文和Scalaz任务,但我正在寻找一些更简单的东西,可以应用于我知道不需要上下文切换的特定地方。(有点类似于对收藏的看法(。

一个更真实的例子是,我有一个记录未来执行时间的函数-没有理由只为了记录时间而进行上下文切换(更不用说现在我正在测量执行时间+执行器获取"onComplete"所花费的时间(

def timedFuture[T](metric: Histogram)(futureBlock: => Future[T])(implicit ec: ExecutionContext): Future[T] = {
val startTime = System.nanoTime()
val result: Future[T] = futureBlock
result onComplete (_ => metric.record((System.nanoTime - startTime) / 1000000))
result
}

如果有严格的/同步的转换要作为一件事执行,请在Try实例上执行转换:

longOperation().transform(_.map(_ * 2).map(_.toString).map(_ + "bla"))

来源:https://viktorklang.com/blog/Futures-in-Scala-protips-5.html

使用不切换的ExecutionContext,如以下所示:

val currentThreadExecutionContext = ExecutionContext.fromExecutor(
new Executor {
def execute(runnable: Runnable) { runnable.run() }
})

从scala-future文档中,也有一些论点建议不要使用这个,因为runnable(回调(可能在意外线程中调用。但是,如果您完全了解异步future/promise的工作原理,就可以使用它。

实际上,在猫的效果或游戏框架中有一些蹦床执行上下文。你可以把这些东西复制到你的项目中。

注意,如果您使用这样的执行上下文,请不要在flatMap/map主体内进行阻塞调用

只要系统中有多个线程,上下文切换就会随时发生,这取决于操作系统。虽然使用.map在一定程度上增加了它在那个确切时刻发生的概率,但这对任何事情都无关紧要,因为切换的确切时刻是无关紧要的(无论如何都超出了你的控制范围(。所以,我不会担心的。

相关内容

最新更新