【问题标题】:How to avoid Await.ready in Scala while using Futures?使用 Futures 时如何在 Scala 中避免 Await.ready?
【发布时间】:2018-01-19 18:59:40
【问题描述】:

我有以下伪代码。 依次调用fetchfetchRecordDetailuploadnotifyUploaded函数。每个函数都返回一个未来事件,但第一个函数返回 Option[T],然后(fetchRecordDetailuploadnotifyUploaded)调用我只需要携带 Some[T] 类型并忽略 None。

不幸的是,我通过太多的Await.ready 调用实现了以下输出。

预期输出

通知列表(UploadResult(a_detail_uploaded), UploadResult(c_detail_uploaded))

代码

def fetch(id: String): Future[Option[Record]] = Future {
    Thread sleep 100
    if (id != "b" && id != "d") {
        Some(Record(id))
    } else None
}

def fetchRecordDetail(record: Record): Future[RecordDetail] = Future {
    Thread sleep 100
    RecordDetail(record.id + "_detail")
}

def upload(recordDetail: RecordDetail): Future[UploadResult] = Future {
    Thread sleep 100
    UploadResult(recordDetail.id + "_uploaded")
}

def notifyUploaded(results: Seq[UploadResult]): Future[Unit] = Future{ println("notified " + results)}

   val result: Future[Unit] = //Final call to 'notifyUploaded' goes here

    Await.ready(result, Duration.Inf)

有人可以通过避免Await.ready 调用来帮助即兴创作此代码吗?

val ids: Seq[String] = Seq("a", "b", "c", "d")
def filterSome(s:String) = fetch(s) map ((s, _)) collect { case (s, Some(v)) => v }
val validData = ids map filterSome
Await.ready(Future.sequence(validData), Duration.Inf)
val records = validData.map(_.value.get.toOption)
val recordDetails = records.flatten map fetchRecordDetail
Await.ready(Future.sequence(recordDetails), Duration.Inf)
val uploadResult = recordDetails.map(_.value.get.toOption).flatten  map upload
Await.ready(Future.sequence(uploadResult), Duration.Inf)
val seqUploadResult = uploadResult.map(_.value.get.toOption)
val result: Future[Unit] =  notifyUploaded(seqUploadResult.flatten)
Await.ready(result, Duration.Inf)

【问题讨论】:

  • 编写而不是等待

标签: scala future


【解决方案1】:

这似乎有效。

Future.sequence(ids.map(fetch))                             //fetch Recs
  .map(_.flatten)                                           //remove None
  .flatMap(rs=> Future.sequence(rs.map(fetchRecordDetail))) //fetch Details
  .flatMap(ds=> Future.sequence(ds.map(upload)))            //upload
  .flatMap(notifyUploaded)                                  //notify

它返回一个Future[Unit],您可以打开Await(),但我不知道为什么。

【讨论】:

  • 你能告诉我最后如何删除 Await 调用吗(根本不使用并在完成时打印结果)?如果我不使用 Await() 调用,我会看到程序退出而没有任何输出。
  • 实际上,这是您真正需要在Future 上使用Await() 的一种情况。如果您的程序无事可做,那么它真的应该在退出之前等待所有未来。
【解决方案2】:

你想要什么?:

  for {
    f1 <- validData
    f2 <- recordDetails
    f3 <- seqUploadResult
  }yield f3
  onComplete(notifyUploaded(seqUploadResult.flatten))

【讨论】:

  • 这样做我收到此错误Exception in thread "main" java.util.NoSuchElementException: None.get。这是因为在代码执行上述 for 循环中的任何变量时,没有一个 Future 对象提供任何 Promise
  • 我明白了。我会检查它
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-19
  • 1970-01-01
  • 2020-10-24
  • 2015-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多