Это неправильно:
for{f <- l; v <- f.value} yield v
Кажется, это работает в вашем случае только потому, что фьючерсы уже выполнены, поэтому их член value
определен. Однако в общем случае они могут еще не выполняться, когда вы выполняете for понимание, и, таким образом, value
вернет None
(несмотря на то, что в какой-то момент они в конечном итоге будут выполнены). Например, попробуйте это в REPL:
val f1 = Future{
Thread.sleep(3000) // Just a test to illustrate, never do this!
1
}
val f2 = Future{
Thread.sleep(3000) // Just a test to illustrate, never do this!
throw new IllegalArgumentException
}
val l = List( f1, f2 )
for{f <- l; v <- f.value} yield v
Результатом является пустой список, потому что ни один из фьючерсов в l
еще не выполнен. Затем подождите немного (не более 3 секунд) и повторно запустите для понимания (последняя строка), и вы получите непустой список, потому что фьючерсы, наконец, выполнены.
Чтобы исправить это, вам придется либо заблокировать (то есть дождаться выполнения всех фьючерсов) с помощью scala.concurrent.Await
, либо остаться в асинхронном мире, используя что-то вроде Future.map
или Future.flatMap
. Например, если вы хотите заблокировать, вы можете сделать:
Await.result( Future.sequence( l ), duration.Duration.Inf )
Await.result
ждет результата будущего, позволяющего перейти из асинхронного мира в синхронный. Результатом вышесказанного является List[Int]
. Проблема в том, что вы теряете случаи сбоя (результат не List[Try[Int]]
, как вы хотели), и фактически повторно генерируете первое исключение. Чтобы исправить это, вы можете использовать этот вспомогательный метод, который я опубликовал в другом ответе: https://stackoverflow.com/a/15776974/1632462 С его помощью вы можете:
Await.result( Future.sequence( l map mapValue ), duration.Duration.Inf )
Это будет ждать, пока все фьючерсы не будут выполнены (либо с правильным значением, либо с ошибкой), и вернет ожидаемый List[Try[Int]]
person
Régis Jean-Gilles
schedule
15.04.2013