Scala - Будущий список сначала завершен с условием

У меня есть список фьючерсов, и я хочу, чтобы первый из них был завершен с определенным условием. Вот пример возможного кода:

val futureList: Future[List[T]] = l map (c => c.functionWithFuture())
val data = for {
           c <- futureList
           }yield c
data onSuccess {
  case x => (x filter (d=> d.condition)).head
}

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

Я знаю firstCompletedOf, но это не то, что я ищу.

(Извините за мой плохой английский.)


person Siliciium    schedule 12.03.2016    source источник


Ответы (1)


Попробуйте использовать Promise и вызвать для него trySuccess, как только будет выполнено будущее, удовлетворяющее условию. Первый вызов trySuccess завершит будущее, последующие не будут иметь никакого эффекта (в отличие от вызова success, который можно вызвать только один раз на Promise).

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

import scala.concurrent.{ Await, Future, Promise }
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.Random

def condition(x: Int) = x > 50

val futures = (1 to 10) map (x => Future {
  // wait a random number of ms between 0 and 1000
  Thread.sleep(Random.nextInt(1000))
  // return a random number < 100
  Random.nextInt(100)
})

val p = Promise[Int]()
// the first one that satisfies the condition completes the promise
futures foreach { _ filter condition foreach p.trySuccess }
val result = p.future

// Watch out: the promise could never be fulfilled if all the futures are <=50
println("The first completed future that satisfies x>50 is: " + Await.result(result, 10.seconds))
person Giovanni Caporaletti    schedule 12.03.2016
comment
Большое спасибо ! Но заставляет ли это решение фильтровать первое завершенное Future? Разве мы не делаем это просто так: ждем завершения первого Future, проверяем его, а затем второе? - person Siliciium; 14.03.2016
comment
Нет, взгляните на future.filter(), это в основном преобразование map, которое генерирует исключение, если условие не выполняется. Для этого требуется контекст выполнения. Операции с будущим никогда не блокируются, пока вы не вызовете Await.result(future, t) :) - person Giovanni Caporaletti; 15.03.2016
comment
позвольте мне добавить, что то же самое для foreach, вы в основном регистрируете обратный вызов. Вы можете проверить это, установив более длительный сон в будущем коде и напечатав что-то после строки futures foreach ..., вы заметите, что это будет напечатано сразу - person Giovanni Caporaletti; 15.03.2016
comment
Ок, прекрасно! Кажется, это работает. Большое спасибо за твою помощь! - person Siliciium; 15.03.2016