복붙노트

[SCALA] 스칼라는 미래의 순서를 기다리고

SCALA

스칼라는 미래의 순서를 기다리고

모두 선물을 기다릴 것 다음처럼 코드를 기대했다,하지만하지 않습니다.

object Fiddle {
  val f1 = Future {
    throw new Throwable("baaa") // emulating a future that bumped into an exception
  }

  val f2 = Future {
    Thread.sleep(3000L) // emulating a future that takes a bit longer to complete
    2
  }

  val lf = List(f1, f2) // in the general case, this would be a dynamically sized list

  val seq = Future.sequence(lf) 

  seq.onComplete {
    _ => lf.foreach(f => println(f.isCompleted))
  }
}

val a = FuturesSequence

나는 seq.onComplete 자체를 완료하기 전에 전체에 모든 대기,하지만 너무 것입니다 가정; 이 결과 :

true
false

.sequence, 나는 내가 (동적 크기) 순서, 또는 무엇의 모든 원래의 미래에 대한 대기 여기에 문제가 될 수 있음을 병렬을 구현하는 것이 궁금 scala.concurrent.Future의 소스에 따라 약간 어려웠다.

편집 : 이와 관련된 질문 : https://worldbuilding.stackexchange.com/questions/12348/how-do-you-prove-youre-from-the-future :)

해결법

  1. ==============================

    1.(실패 없음) 모든 결과를 기다리고에 대한 하나의 일반적인 접근 방식은 미래 안에 새로운 표현으로 "리프트"실패하는 것입니다 그래서 어떤 결과에 완전한 모든 선물 (그들은 실패를 나타내는 결과로 완료 할 수 있지만). 이 얻을 수있는 한 자연적인 방법은 시도 리프팅입니다.

    (실패 없음) 모든 결과를 기다리고에 대한 하나의 일반적인 접근 방식은 미래 안에 새로운 표현으로 "리프트"실패하는 것입니다 그래서 어떤 결과에 완전한 모든 선물 (그들은 실패를 나타내는 결과로 완료 할 수 있지만). 이 얻을 수있는 한 자연적인 방법은 시도 리프팅입니다.

    선물의 트위터의 구현이 사소한 만드는 liftToTry 방법을 제공하지만, 당신은 표준 라이브러리의 구현과 비슷한 작업을 수행 할 수 있습니다

    import scala.util.{ Failure, Success, Try }
    
    val lifted: List[Future[Try[Int]]] = List(f1, f2).map(
      _.map(Success(_)).recover { case t => Failure(t) }
    )
    

    모든 미래가 완료, 시도를 사용하여 성공과 실패를 나타낼 때 이제 Future.sequence는 (해제) 완료됩니다.

    그리고, 실행 상황을 가정하고, 다음과 같이 보일 수 있습니다 미래의 시퀀스의 모든 원래의 선물을 기다리고에 대한 일반적인 솔루션은 물론 암시 적으로 사용 가능하다.

      import scala.util.{ Failure, Success, Try }
    
      private def lift[T](futures: Seq[Future[T]]) = 
        futures.map(_.map { Success(_) }.recover { case t => Failure(t) })
    
      def waitAll[T](futures: Seq[Future[T]]) =
        Future.sequence(lift(futures)) // having neutralized exception completions through the lifting, .sequence can now be used
    
      waitAll(SeqOfFutures).map { 
        // do whatever with the completed futures
      }
    
  2. ==============================

    2.Future.sequence에 의해 생성되는 미래 때 중 하나를 완료합니다

    Future.sequence에 의해 생성되는 미래 때 중 하나를 완료합니다

    두 번째 포인트는 귀하의 경우에는 무슨 일이 일어나고 있는지, 그리고 포장의 미래는 실패의 경우에 하나의 Throwable를 저장할 수 있기 때문에, 즉시 포장 미래 중 하나가 실패로 완료하는 데 의미가 있습니다. 결과는 같은 실패 할 수 있기 때문에 다른 선물을 기다리는 의미가 없다.

  3. ==============================

    3.이것은 이전의 대답을 지원하는 예입니다. 단지 표준 스칼라 API를 사용하여이 작업을 수행하는 쉬운 방법이있다.

    이것은 이전의 대답을 지원하는 예입니다. 단지 표준 스칼라 API를 사용하여이 작업을 수행하는 쉬운 방법이있다.

    예, 나는 3 미래를 만드는 오전. 다음은 5, 7에 완료, 각각 구초합니다. 모든 선물이 해결 될 때까지 Await.result에 대한 호출은 차단합니다. 3 개 선물이 완료되면,이 목록 (5,7,9)으로 설정되고 실행이 계속됩니다.

    예외가 선물의에 던져 경우 또한, Await.result 즉시 차단을 해제하고 예외가 발생합니다. 주석 예외 (...) 라인은 행동이를 볼 수 있습니다.

      try {
        val a = Await.result(Future.sequence(Seq(
          Future({
            blocking {
              Thread.sleep(5000)
            }
            System.err.println("A")
            5
          }),
          Future({
            blocking {
              Thread.sleep(7000)
            }
            System.err.println("B")
            7
            //throw new Exception("Ha!")
          }),
          Future({
            blocking {
              Thread.sleep(9000)
            }
            System.err.println("C")
            9
          }))),
          Duration("100 sec"))
    
        System.err.println(a)
      } catch {
        case e: Exception ⇒
          e.printStackTrace()
      }
    
  4. ==============================

    4.우리는 서열 번호 풍요롭게 [미래를 [T]] 암시 클래스를 통해 자신의 onComplete 방법 :

    우리는 서열 번호 풍요롭게 [미래를 [T]] 암시 클래스를 통해 자신의 onComplete 방법 :

      def lift[T](f: Future[T])(implicit ec: ExecutionContext): Future[Try[T]] =
        f map { Success(_) } recover { case e => Failure(e) }
    
      def lift[T](fs: Seq[Future[T]])(implicit ec: ExecutionContext): Seq[Future[Try[T]]] =
        fs map { lift(_) }
    
      implicit class RichSeqFuture[+T](val fs: Seq[Future[T]]) extends AnyVal {
        def onComplete[U](f: Seq[Try[T]] => U)(implicit ec: ExecutionContext) = {
          Future.sequence(lift(fs)) onComplete {
            case Success(s) => f(s)
            case Failure(e) => throw e // will never happen, because of the Try lifting
          }
        }
      }
    

    그런 다음, 특정 MWE에, 당신이 할 수 있습니다 :

      val f1 = Future {
        throw new Throwable("baaa") // emulating a future that bumped into an exception
      }
    
      val f2 = Future {
        Thread.sleep(3000L) // emulating a future that takes a bit longer to complete
        2
      }
    
      val lf = List(f1, f2)
    
      lf onComplete { _ map {
        case Success(v) => ???
        case Failure(e) => ???
      }}
    

    이 솔루션은 하나의 미래에서와 마찬가지로 당신이 미래의 순서 상 onComplete를 호출 할 수있는 장점이있다.

  5. ==============================

    5.추가 농구를 피하기 위해 시도로 미래를 만듭니다.

    추가 농구를 피하기 위해 시도로 미래를 만듭니다.

    implicit val ec = ExecutionContext.global
    
    val f1 = Future {
      Try {
        throw new Throwable("kaboom")
      }
    }
    
    val f2 = Future {
      Try {
        Thread.sleep(1000L)
        2
      }
    }
    
    Await.result(
      Future.sequence(Seq(f1, f2)), Duration("2 sec")
    ) foreach {
      case Success(res) => println(s"Success. $res")
      case Failure(e)   => println(s"Failure. ${e.getMessage}")
    }
    
  6. from https://stackoverflow.com/questions/29344430/scala-waiting-for-sequence-of-futures by cc-by-sa and MIT license