scala期货顺序延迟执行

scala futures sequential lazy execution

我有一个 iterable 期货,每个期货都返回一个序列:Iterable[Future[Seq[Int]]] 因此,我需要一个序列,它是从期货返回的序列的串联:Seq[Int]

问题是我只需要结果序列的第一个 n 元素,所以我并不总是需要执行所有的期货。我也事先不知道需要执行多少个future才能实现(也许第一个返回就够了,也许我们要全部执行)。

显然,我需要按顺序执行我的功能。我可以做 foreach 和 break/return,但我想用函数式的方式来表达。


以下似乎工作并且"看起来"功能。我对这将如何实际执行或在幕后采取行动的了解有限。

这可以很容易地被放入一个 def 中,其中硬编码的 4 被传递一个参数。

我认为我应该返回 5 个元素,即使只请求了 4 个元素,因为对中间未来的评估需要以任何一种方式进行。删除多余的元素应该很简单。

1
2
3
4
5
6
7
8
9
10
11
12
13
val f = Iterable(Future(Seq(1,2,3)), Future(Seq(4,5)), Future(Seq(6,7,8)))

val output = f.foldLeft(Future(Seq.empty[Int])){(previous, next) =>
    previous.flatMap{pSeq =>
        if(pSeq.length >= 4) {
            Future(pSeq)
        } else {
            next.map(nSeq => pSeq ++ nSeq)
        }
    }
}

println(Await.result(output, Duration.Inf)) //List(1,2,3,4,5)

我不喜欢将 pSeq package在 Future 中只是为了保持一致的类型。

编辑:只是对 viktor 回答的回应(我无法发表评论,因为代表不够高,它稍微增加了我的回答的价值)。

即使 Viktor 的答案更容易阅读,它也必须等待所有 Futures 完成,即使它们不是必需的。

例如,将我的 f 替换为以下内容:

1
val f = Iterable(Future(Seq(1,2,3)), Future(Seq(4,5)), Future(throw new Exception))

它仍然可以工作,Viktor 调用 Future.sequence 将一个 Iterable[Future[]] 转换为一个 Future[Iterable[]],因此必须完成所有操作。


你要么使用 Future.fold:

1
2
3
4
5
6
7
8
9
scala> import scala.concurrent._

scala> import ExecutionContext.Implicits.global

scala> Future.fold(Iterable(Future(Seq(1,2,3)), Future(Seq(4,5)), Future(Seq(6,7,8))))(Seq.empty[Int])( (prev, cur) => if(prev.size >= 4) prev else prev ++ cur) foreach println

List(1, 2, 3, 4, 5)

scala>

或者您查看 Future.fold 是如何实现的,然后添加退出条件。 (本质上是一个 foldUntil)