Scala Future.find

Scala Future.find,scala,future,scala-2.12,Scala,Future,Scala 2.12,Scala 2.12有2个未来。查找方法 @deprecated("use the overloaded version of this method that takes a scala.collection.immutable.Iterable instead", "2.12.0") def find[T](@deprecatedName('futurestravonce) futures: TraversableOnce[Future[T]])(@deprecatedName('predi

Scala 2.12有2个
未来。查找
方法

@deprecated("use the overloaded version of this method that takes a scala.collection.immutable.Iterable instead", "2.12.0")
def find[T](@deprecatedName('futurestravonce) futures: TraversableOnce[Future[T]])(@deprecatedName('predicate) p: T => Boolean)(implicit executor: ExecutionContext): Future[Option[T]]
以及它的重载版本

def find[T](futures: scala.collection.immutable.Iterable[Future[T]])(p: T => Boolean)(implicit executor: ExecutionContext): Future[Option[T]]
两者的描述相同

因此,我假设这些方法在给定的列表中找到与param
p
匹配的第一个完成的
Future

但实际上只有第一个是这样做的

  val start = System.currentTimeMillis
  val a = (1 to 3).reverse.iterator.map{ x =>
    Future{
      Thread.sleep(x * 10000)
      x
    }
  }
  val b = Future.find(a)(_.isInstanceOf[Int])
  b.foreach{ x =>
    println(x)
    println(System.currentTimeMillis - start) // 10020 
  }
该方法的不推荐版本返回最快的版本

  val a = (1 to 3).reverse.map{ x =>
    Future{
      Thread.sleep(x * 10000)
      x
    }
  }
  val b = Future.find(a)(_.isInstanceOf[Int])
  b.foreach{ x =>
    println(x)
    println(System.currentTimeMillis - start)
  }
重载版本返回最慢的版本。更准确地说,它只是从头到尾检查给定的列表,而不在乎完成这些列表需要多长时间

应该是这样的吗?如果是这样的话,使用复制的还是自己实现它是唯一关心它们的完成时间的选项?

您是对的,在2.12.x中期望一次
可遍历的[Future[T]
与替换
Future.find的行为不同。正如您从下面粘贴的源代码中看到的,前一种
find
方法利用
Promise
tryComplete
有效地从输入集合捕获第一个完成的未来,而后一种方法使用一个简单的
hasNext/next
遍历:

@deprecated("use the overloaded version of this method that takes a scala.collection.immutable.Iterable instead", "2.12.0")
def find[T](@deprecatedName('futurestravonce) futures: TraversableOnce[Future[T]])(@deprecatedName('predicate) p: T => Boolean)(implicit executor: ExecutionContext): Future[Option[T]] = {
  val futuresBuffer = futures.toBuffer
  if (futuresBuffer.isEmpty) successful[Option[T]](None)
  else {
    val result = Promise[Option[T]]()
    val ref = new AtomicInteger(futuresBuffer.size)
    val search: Try[T] => Unit = v => try {
      v match {
        case Success(r) if p(r) => result tryComplete Success(Some(r))
        case _ =>
      }
    } finally {
      if (ref.decrementAndGet == 0) {
        result tryComplete Success(None)
      }
    }

    futuresBuffer.foreach(_ onComplete search)

    result.future
  }
}

def find[T](futures: scala.collection.immutable.Iterable[Future[T]])(p: T => Boolean)(implicit executor: ExecutionContext): Future[Option[T]] = {
  def searchNext(i: Iterator[Future[T]]): Future[Option[T]] =
    if (!i.hasNext) successful[Option[T]](None)
    else {
      i.next().transformWith {
        case Success(r) if p(r) => successful(Some(r))
        case other => searchNext(i)
      }
    }
  searchNext(futures.iterator)
}
实现您自己的方法之一可能是将带有添加谓词的
Future.firstCompletedOf
方法扩展为如下内容:

def firstConditionallyCompletedOf[T](futures: List[Future[T]])(p: T => Boolean)(implicit ec: ExecutionContext): Future[T] = {
  val p = Promise[T]()
  val firstCompleteHandler = new AtomicReference[Promise[T]](p) with (Try[T] => Unit) {
    override def apply(v1: Try[T]): Unit = getAndSet(null) match {
      case null => ()
      case some => some tryComplete v1
    }
  }
  futures.foreach{ _.filter(condition).onComplete(firstCompleteHandler) }
  p.future
}

你说的“最慢的”或“最快的”是什么意思?在第二个例子中,因为
a
是一个
迭代器
;它将被
val c=Future.firstCompletedOf(a)
val b=Future.find(a)([Int])
将获得一个空的
迭代器
@SarveshKumarSingh删除该行。这是某种复制粘贴错误
def firstConditionallyCompletedOf[T](futures: List[Future[T]])(p: T => Boolean)(implicit ec: ExecutionContext): Future[T] = {
  val p = Promise[T]()
  val firstCompleteHandler = new AtomicReference[Promise[T]](p) with (Try[T] => Unit) {
    override def apply(v1: Try[T]): Unit = getAndSet(null) match {
      case null => ()
      case some => some tryComplete v1
    }
  }
  futures.foreach{ _.filter(condition).onComplete(firstCompleteHandler) }
  p.future
}