2015-05-11 5 views
2

Если у меня есть некоторые вычисления, что занимает некоторое время, я мог бы поместить его в scala.concurrent.Future:Scala Futures - flatMap и OnFailure

val f = Future { someLongRunningFunction() } 

и давайте говорить, что я хочу сделать что-то еще асинхронно раз, что вычисление завершается:

f.flatMap{ _ => anotherLongRunningFunction() } 

В том случае, если первоначальный блок f «s терпит неудачу, как я„идиоматически“справиться с этим при использовании flatMap или других комбинаторов? Это всего лишь случай использования recover или onFailure до flatMap?

Мне нравится элегантность и простота использования flatMap, но кажется, что сценарии неудач мешают ему.

Редактировать: второе будущее зависит от первого, отсюда flatMap. Я ищу решение, которое изящно позволит мне подключаться, как я бы, с flatMap, но также обрабатывать отказы первого.

+1

Второй метод зависит от результата первого? Вы также заботитесь о возвращенной стоимости? –

+0

Да, это так, поэтому заказ. –

+0

Хорошо, хорошо .. что произойдет, если 'f' не удастся? Почему нужно беспокоиться о том, чтобы запустить второе будущее, если это зависит от первого? Как мы можем выздороветь? Что вы хотите и когда? –

ответ

2

Если у вас есть несколько фьючерсов, вы можете разместить их для понимания.

val futureResult = for { 
    result1 <- future1 
    result2 <- future2 
    ... 
} yield { 
    //computation with results 
} 

Вы можете добавить recover в конце в случае, если вы хотите обработать любое исключение, вы можете найти:

futureResult.recover{ 
    case exceptionResult: Throwable => // Process exception 
} 

Я думаю, что это более чистый, что с помощью flatMap.

+2

Я не думаю, что ОП обязательно хочет «восстановить» в конце - это неясно. Это просто перефразирование «flatMap» для понимания. –

+0

Точно. Будущее 2 зависит от Первого 1, заканчивающегося первым; следовательно, звонок flatMap. –

+0

В этом случае ознакомьтесь с [scala async library] (https://github.com/scala/async). Это также может помочь. Но если вам нужно сначала завершить первое будущее, я бы разрешил его, проверил результаты и затем разрешил второй. «FlatMap» присоединится к обоим вычислениям. –

2

Цитирую scaladoc для flatMap:

создает новое будущее, применяя функцию к успешному результату этого будущего, и возвращает результат функции в качестве нового будущего. Если это будущее будет завершено с исключением, то новое будущее также будет содержать это исключение.

Обратите внимание на жирный шрифт, что означает, что все, что вы передадите в flatMap, будет выполнено только в том случае, если начальное будущее завершится успешно.

Таким образом, вы должны обращаться только результат всего исполнения:

val result = future1.flatMap { 
    result => functionReturningFuture2(result) 
} 

, а затем:

result.onFailure // or 
result.onSuccess // or 
result.recover 
0

Я только начиная с будущего, но вот некоторые идеи.

Если вы действительно хотите использовать flatMap, вам необходимо включить сбой в состояние неуверенности.

for{ a <- f recover r 
    b <- another(a) 
} yield b 

Это работает, если возвращаемый тип r является :> тип результата f.

Или вы можете передать вопрос о том, что делать с провалом на следующий процесс

for{ a <- f map (x => Success(x)) recover (ex => Failure(ex)) 
    b <- another(a) 
} yield b 

Здесь тип аргумента another будет Try[T] где тип f является Future[T].