При составлении фьючерсов со структурой for-yield, некоторые с побочными эффектами, некоторые без, я ввел условие гонки, потому что будущее, зависящее от побочного эффекта, не принимает результат этого побочного эффекта future в качестве аргумента.
Короче:
future b читает значение, которое изменено побочным эффектом от future a, но future a явно не зависит от результата future < strong> 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
. Это эффективно создает граф зависимостей, который не может быть инициирован createConnection до завершения existsInAnyDirection.
Теперь вопрос:
Есть ли более разумный способ сделать зависимость явной?
Бонусная информация
Мои собственные исследования говорят мне, что Scala Futures просто не очень хорошо справляется с побочными эффектами. Методы признака Future, которые работают с побочными эффектами, возвращаются Unit, хотя вполне могут быть результаты для чтения из операции побочного эффекта, то есть коды ошибок, сгенерированные идентификаторы, на самом деле любая другая метаинформация.
flatMap
не работает. Существует важное различие в том, когда вы создаетеFuture
- внутриflatMap
или снаружи - это повлияет на время началаFuture
. Возможно, это та деталь, которую вы упустили, и поэтому вы получаете состояние гонки.val f = Future { 5 }; val h = for { x <- f ...
не то же самое, чтоval h = for { x <- Future { 5 } ...
- первый запускаетFuture
раньше, чем второй. - person yǝsʞǝla   schedule 26.01.2016scanner
- этоval
, тогда вашFuture
уже запущен до того, как вы вошли вfor
понимание. Если этоdef
, значит, нет. Похоже, вам нужно сделать свойfutureScannedUser
adef
или функцию() => Future[?]
- person yǝsʞǝla   schedule 26.01.2016