有连续的Future.find吗?

时间:2014-10-18 10:54:52

标签: scala stream functional-programming future sequential

我有一些副作用,

def f(): Future[Int] = {
  val n = Random.nextInt()
  println(s"Generated $n")
  Future(n)
}

我想重复执行它,直到谓词返回true。

def success(n: Int): Boolean = n % 2 == 0

我的计划是构建Stream结果

val s = Stream.fill(10)(f)

然后使用Future.find获取满足谓词的第一个结果。

Future.find(s)(success) map println

问题是Future.find并行运行所有期货,我希望它依次执行期货,直到谓词返回true。

scala> Future.find(s)(success) map println
Generated -237492703
Generated -935476293
Generated -1155819556
Generated -375506595
Generated -912504491
Generated -1307379057
Generated -1522265611
Generated 1163971151
Generated -516152076
res8: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@37d28f02
Some(-1155819556)

问题是如何按顺序执行期货流,直到谓词返回true为止?标准或第三方库中是否有合适的功能?

3 个答案:

答案 0 :(得分:4)

而不是使用Stream我建议使用另一种方法。使用The Future的过滤器并以递归方式恢复:

def findFirst[A](futureGen: => Future[A], predicate: A => Boolean): Future[A] = {
  futureGen.filter(predicate).recoverWith { case _ => findFirst(futureGen, predicate) }
}

findFirst(f, success)

这会一个接一个地打电话给期货,直到'成功'将返回真实。

答案 1 :(得分:1)

首先,让我们不感兴趣的未来失败:

val s1 = s.map(_.filter(success))

现在你可以结合两个这样的未来,并使用fallbackTo获得第一个成功的价值。只是折叠流,从一个已知不好的未来开始:

def firstSuccess[T](stream: Stream[Future[T]]): Future[T] = 
  if (stream.isEmpty)
    Future.failed(new NoSuchElementException)
  else
    stream.head.fallbackTo(firstSuccess(stream.tail))

答案 2 :(得分:0)

如果我理解了这个问题,那么你将不得不阻止线程按顺序进行。您可以使用Await来实现这一目标。

scala> def f(): Future[Int] = {
 |   val n = Random.nextInt()
 |   println(s"Generated $n")
 |   Future(n)
 | }
f: ()scala.concurrent.Future[Int]

scala> def success(n: Int): Boolean = n % 2 == 0
success: (n: Int)Boolean

scala> val s = Stream.fill(10)(f)

用你的方式,我得到了

scala> Future.find(s)(success) map println
Generated 551866055
Generated -561348666
Generated -1103407834
Generated -812310371
Generated -1544170923
Generated 2131361419
Generated -236722325
Generated -1473890302
Generated -82395856
Some(-561348666)
res16: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@15a2d71

我应该得到一些答案(-561348666),你可以得到

scala> s.find(x => success(Await.result(x,1 seconds))).get onSuccess {case p=> println(p)}
-561348666