Scala: 用于 future for-comprehension 的 ExecutionContext

7
当我创建一个 `future`,或者应用 `onSuccess` 和 `map` 等方法时,我可以为它们指定 `ExecutionContext`。
例如,
val f = future {
  // code
} executionContext

f.map(someFunction)(executionContext)

f onSuccess {
  // code
} executionContext

然而,如果我使用一个future的for-comprehension,我怎样才能为yield部分指定ExecutionContext呢?

for {
  f <- future1
  g <- future2
} yield {
  // code to be executed after future1 onSuccess and future2 onSuccess
  // What ExecutionContext runs this code?
} // (executionContext) here does not work

如果没有指定,那么在yield中运行代码的ExecutionContext是什么?


编辑

好的,得到答案之后,我发现如下内容:
如果我不定义或导入隐式ExecutionContext(例如Implicits.global), 则for-comprehension无法编译。这意味着for-comprehension使用隐式ExecutionContext。

那么,如何在没有隐式ExecutionContext的情况下使用for-comprehension,即如何指定ExecutionContext?


如果您没有指定implicit,则for推导式无法编译。请查看我的答案以了解其根本原因。 - mikołak
@flavian 在简单情况下,这是有效的。但如果有两个ExecutionContext用于for-comprehension,我该如何指定?它会显示类似“ambiguous implicit values”的错误。我可以每次定义或导入implicit vals或defs和for-comprehension时都进行阻塞,但是否还有其他方法? - Naetmul
你是指一个带有多个生成器的单个for推导式(在这种情况下,flavian的答案有效),还是多个连续的for推导式?为了确保准确性,请确认一下。 - mikołak
@TheTerribleSwiftTomato 我的意思是使用多个生成器的单个for-comprehension。解决方案并不简单,但似乎Scala不支持for-comprehension的显式ExecutionContext... - Naetmul
2个回答

9

ExecutionContext 参数是 implicit 的。这意味着您可以:

import scala.concurrent.ExecutionContext

implicit val context = ExecutionContext.fromExecutor(//etc)
for {
  f <- future1
  g <- future2
} yield {
  // code to be executed after future1 onSuccess and future2 onSuccess
  // What ExecutionContext runs this code?: the one above.
}

您还拥有一个默认值,即scala.concurrent.ExecutionContext.Implicits.global。它的线程数与运行中的处理器数量相同。

默认情况下,并不是所有的Futures都会使用它,您仍需导入它。

更新: 如果您真的想指定,虽然并不推荐,您可以取消for yield的封装。

val combined = futureA.flatMap(x => futureB)(context)

如果有两个隐式的ExecutionContext在作用域内,而您需要选择一个,该怎么办? - kostya
1
@kostya,你可以使用选择性别名来解决问题,就像这样:import com.bla.bla.{ contextToDiscard => _, _ }。如果它是导致问题的包导入,那么这将只会在范围内导入一个。另一种方法是将带有执行器的导入移动到较低的作用域。 - flavian

1

由于for推导式被“映射”到map/flatMap操作,并且这些操作的ExecutionContext参数是隐式的,所以我猜你可以尝试在本地作用域添加一个implicit val

implicit val myContext:ExecutionContext = ...

.

我不相信存在“默认”的隐式ExecutionContext,但最常用的是 ExecutionContext.Implicits.global

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接