Scala Futures 用于理解值列表

Scala Futures for-comprehension with a list of values

我需要同时对列表中的某些元素执行 Future 方法。我当前的实现是按顺序工作的,这对于节省时间来说并不是最佳选择。我通过映射我的列表并在每个元素上调用方法并以这种方式处理数据来做到这一点。

我的经理与我分享了 link 展示了如何使用 for-comprehension 同时执行 Futures 但我无法 see/understand 如何使用我的 List 来实现它。

他分享给我的link是https://alvinalexander.com/scala/how-use-multiple-scala-futures-in-for-comprehension-loop/

这是我当前的代码:

private def method1(id: String): Tuple2[Boolean, List[MyObject]] = {
    val workers = List.concat(idleWorkers, activeWorkers.keys.toList)
    var ready = true;
    val workerStatus = workers.map{ worker =>
      val option =  Await.result(method2(worker), 1 seconds)
      var status = if (option.isDefined) {
        if (option.get._2 == id) {
          option.get._1.toString
        } else {
          "INVALID"
        }
      } else "FAILED"
      val status = s"$worker: $status"
      if (option.get._1) {
        ready = false
      }
      MyObject(worker.toString, status)
    }.toList.filterNot(s => s. status.contains("INVALID"))
    (ready, workerStatus)
  }

  private def method2(worker: ActorRef): Future[Option[(Boolean, String)]] = Future{
      implicit val timeout: Timeout = 1 seconds;
      Try(Await.result(worker ? GetStatus, 1 seconds)) match {
            case Success(extractedVal) => extractedVal match {
                case res: (Boolean, String) => Some(res)
                case _ => None
            }
            case Failure(_) => { None }
            case _ => { None }
        }
  }

如果有人可以建议如何在这种情况下实现 for-comprehension,我将不胜感激。谢谢

对于 method2,不需要 Future/Await 组合。只是 map Future:

def method2(worker: ActorRef): Future[Option[(Boolean, String)]] =
  (worker ? GetStatus).map{
      case res: (Boolean, String) => Some(res)
      case _ => None
    }

对于method1你同样需要mapmethod2的结果并在map中进行处理。这将使 workerStatus 变成 List[Future[MyObject]] 并且意味着一切并行运行。

然后用Future.sequence(workerStatus)List[Future[MyObject]]变成Future[List[MyObject]]。然后您可以再次使用 mapList[MyObject] 进行过滤/检查。这将在所有个人 Future 完成后发生。

理想情况下,您会 return 来自 method1Future 以保持所有异步。如果绝对必要,您可以在此时使用 Await.result,这将等待所有异步操作完成(或失败)。