2017-12-05 2 views
0

를 사용하는 경우, 두 번째 의존 Future 다시 호출 Future(<not completed>)Future.onComplete되면 항상. 2 개의 Future을 사용하는 다른 구성에서는이 동작이 발생하지 않습니다.미래 (<완료되지 않은>) Future.map 연결자 첫 번째 <code>Future</code>을 처리하는 <code>Future.map</code>을 사용한 후

미래가 분명히 완료되지 않은 이유는 누구나 Future.onComplete이 호출되는 이유를 설명 할 수 있습니까?

스칼라 2.12.3이 사용됩니다. 필요한 경우이 문제를 평가하려면 다음을 잘라내어 붙여 넣으십시오.

import scala.collection.mutable.ListBuffer 
import scala.concurrent.ExecutionContext.Implicits.global 
import scala.concurrent.Future 
import scala.util.{Failure, Success} 


object FutureNotCompleted { 

    def threadNumber: String = f"${Thread.currentThread().getId.toInt}%2d" 

    ///////////////////////////////////////////////////// 
    // Future completion control 
    ///////////////////////////////////////////////////// 

    var futures: ListBuffer[Future[Any]] = ListBuffer() 

    def add(future: Future[Any]): Unit = synchronized(futures += future) 

    def remove(future: Future[Any]): Unit = synchronized(futures = futures.filter(_ != future)) 

    def loopTillCompleted: Unit = { 
    var futuresOnList = true; 

    while (futuresOnList) { 
     Thread.sleep(100) 
     for (future <- futures) { 
     if (future.isCompleted) { 
      future.value.get match { 
      case Success(v) => println(s"${threadNumber} Success: ${v}") 
      case Failure(e) => println(s"${threadNumber} Error: ${e}") 
      } 
      remove(future) 
     } 
     } 
     if (futures.size == 0) futuresOnList = false 
    } 
    } 

    ///////////////////////////////////////////////////// 
    // Future factory 
    ///////////////////////////////////////////////////// 

    def createRegisteredFuture: Future[Int] = { 
    val future = createFuture 
    add(future) 
    future 
    } 

    def createFuture: Future[Int] = Future { 
    val i = (Math.random() * 1000).toInt 
    println(s"${threadNumber} Future work start: ${i}") 
    Thread.sleep((Math.random() * 1000).toLong) 
    println(s"${threadNumber} Future work stop: ${i}") 
    if (Math.random > 0.7) throw new RuntimeException(s"${threadNumber} Error for ${i}") 
    i 
    } 

    ///////////////////////////////////////////////////// 
    // Functions exhibiting Future use conditions 
    ///////////////////////////////////////////////////// 

    def futureDoesNotComplete: Unit = { 

    val f1 = createRegisteredFuture 
    val f2 = f1.map { 
     i => createRegisteredFuture 
    } 
    // This is never completed at the time the 'onComplete' callback is called 
    f2.onComplete({ 
     case Success(j) => println(s"${threadNumber} j: ${j} ") 
     case Failure(e) => println(s"${threadNumber} f2 Failure: ${e}") 
    }) 

    loopTillCompleted 
    println(s"${threadNumber} All done.") 
    } 

    def futureCompletes: Unit = { 

    val f1 = createRegisteredFuture 

    f1.onComplete({ 
     case Success(i) => { 
     val f2 = createRegisteredFuture 
     f2.onComplete({ 
      case Success(j) => println(s"${threadNumber} i: ${i} j: ${j} ${i}+${j}=${i + j}") 
      case Failure(e) => println(s"${threadNumber} f2 Failure: ${e}") 
     }) 
     } 
     case Failure(e) => println(s"${threadNumber} f1 Failure: ${e}") 
    }) 

    loopTillCompleted 
    println(s"${threadNumber} All done.") 
    } 

    def futureCompletesFor: Unit = { 

    for { 
     f1 <- createRegisteredFuture 
     f2 <- createRegisteredFuture 
    } yield { 
     println(s"f1: ${f1} f2: ${f2}: f1+f2=${f1+f2}") 
    } 

    loopTillCompleted 
    println(s"${threadNumber} All done.") 
    } 

    def main(a: Array[String]): Unit = { 
    // futureCompletes 
    futureDoesNotComplete 
    // futureCompletesFor 
    } 

} 

답변

0

나는 여기에 원하는 동작이 정확히 무엇인지 100 % 확실하지 않다,하지만 난 정말 내가 생각하는 모든 미래의 체인을 onComplete를하려면, 여기 flatMap 시도 할 것입니다. 이것이 문제라면, 당신은 바깥 미래를 완성하는 것입니다, 그리고 그것은 제가 (평면) 맵핑과 동일하게 사용하는 (이후에) 사용할 때부터 의심 스럽습니다.

10 Future work start: 791 
10 Future work stop: 791 
11 Future work start: 819 
11 Future work stop: 819 
11 j: 819 
1 Success: 791 
1 Success: 819 
1 All done. 

여기에서 createRegisteredFuture는 미래를 생성하므로이 맵을 flatMap으로 변경합니다.

val f2 = f1.flatMap { 
     i => createRegisteredFuture 
} 
+0

것은 내가이 페이지의 예제를 통해 일하는 : http://docs.scala-lang.org/overviews/core/futures.html#functional-composition-and-for-comprehensions. 해당 페이지 하나의 중간에 는 발견 : '발 rateQuote = 미래 { connection.getCurrentValue (USD) } 발 구매 = rateQuote지도 {인용 => 경우 (isProfitable (따옴표)) connection.buy을 (양, 따옴표) 다른 가}' 어디'connection.buy'가있다)) ("수익성이 없다" } 구매는 onSuccess {_ =>에 println ("구매"+ 양 + "USD" 경우 새로운 예외를 던져 미래. 제공된 예를 재현 한 것처럼 보입니다. 아마 아닐거야. –

+0

이 예제와 예제의 주된 차이점은 콜백 예제에서 한 가지 더 미래를 감안한 다음 해당 페이지의 맵 예제에서 사라진다는 점입니다. 코드에서 맵핑 할 때 Future [Int [Int]]를 얻게됩니다. 'val f2 : Future [Future [Int]] = ...'에 명시 적으로 타입을 설정하면 이것을 검증 할 수 있습니다. – ameer

관련 문제