2

在构建具有收益结构的期货时,有些有副作用,有些没有,我引入了竞争条件,因为依赖于副作用的未来没有将副作用的结果作为论据。

简而言之:

未来b读取的值因来自未来a的副作用而改变 ,但未来a不明确依赖于未来b的结果,因此可能在b完成读取之前发生。

为了解决这个问题,我的同事引入了一个虚拟函数,将b的结果作为参数并简单地将其丢弃。这样做是为了使依赖关系明确。

实际代码在这里:

  val futureConnection:Future[(Either[String, (Connection)],Boolean)] =
    for {
      scannerUser <- scanner.orFail("Scanning user not found")
      scannedUser <- futureScannedUser.orFail("Scanned user not found")
      existsInAnyDirection <- connections.existsInAnyDirection(scannerUser, scannedUser)
      connection <- connections.createConnection(scannerUser, scannedUser, form.magicWord, existsInAnyDirection)
    } yield {
      (connection, existsInAnyDirection)
    }

在这种情况下,未来b

connections.existsInAnyDirection(scannerUser, scannedUser)

带有虚拟参数的未来a

connections.createConnection(scannerUser, scannedUser, form.magicWord, existsInAnyDirection)

请注意,该参数existsInAnyDirection从未在内部使用createConnection。这有效地创建了在 existsInAnyDirection 完成之前无法启动 createConnection 的依赖关系图。

现在的问题:

有没有更明智的方法来明确依赖关系?


奖金信息

我自己的挖掘告诉我,Scala Futures 根本不能很好地处理副作用。Future trait上处理副作用的方法返回 Unit,而从副作用操作中读取的结果很可能,即错误代码、生成的 ID、任何其他元信息,真的。

4

1 回答 1

0

Future正在处理延迟计算的副作用,例如A => Future[B].

你试图混合几种不同的副作用,但只合成了其中一种Future[_]

尝试选择第二个容器,这可以是 Product 或 State,这取决于您的副作用并考虑副作用的构成方式(可能您需要 mod 和转换器)。在您的代码看起来像(最简单的情况)之后:

for {
  scannerUser <- scanner.orFail("Scanning ...")
  (scannedUser, magicWord) <- futureScannedUser.orFail("Scanned ...")      
  connection <- connections.createConnection(scannerUser, scannedUser, magicWord)
} yield {
  (connection, existsInAnyDirection)
}

// OR

for {
  (scannerUser, state) <- scanner.orFail("Scanning ...")
  (scannedUser, nextState) <- futureScannedUser(state).orFail("Scanned ...")      
  connection <- connections.createConnection(scannerUser, scannedUser, nextState)
} yield {
  (connection, existsInAnyDirection)
}
于 2016-01-26T09:11:06.423 回答