Nach einem Future.map
mit den ersten Future
, die zweiten abhängigen Future
zu verarbeiten ist immer Future(<not completed>)
einmal Future.onComplete
wieder aufgerufen wird. Andere Konstruktionen, die zwei Future
s verwenden, zeigen dieses Verhalten niemals.Zukunft (<nicht abgeschlossen>), wenn Future.map Combinator
Kann jemand erklären, warum Future.onComplete
aufgerufen wird, obwohl die Zukunft anscheinend nicht abgeschlossen ist?
Scala 2.12.3 wird verwendet. Ausschneiden und einfügen, um dieses Problem bei Bedarf zu bewerten.
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
}
}
ich durch Beispiele auf dieser Seite arbeiten: http://docs.scala-lang.org/overviews/core/futures.html#functional-composition-and-for-comprehensions. In der Mitte dieser Seite findet man: 'val rateQuote = Zukunft { connection.getCurrentValue (USD) } val Kauf = rateQuote Karte {quote => if (isProfitable (Zitat)) connection.buy (Menge, Zitat) sonst throw new Exception ("nicht rentabel") } Kauf onSuccess { Fall _ => println ("gekauften" + + Betrag "USD") } ' Wo' connection.buy' ist ein 'Zukunft'. Es schien, dass ich das bereitgestellte Beispiel reproduziert hatte. Vielleicht nicht. –
Der Hauptunterschied zwischen diesem Beispiel und Ihrem Beispiel besteht darin, dass sie im Beispiel der Rückrufe eine weitere Umbruch-Zukunft haben und dann bemerken, dass sie im Kartenbeispiel auf dieser Seite verschwindet. Du bekommst eine Zukunft [Zukunft [Int]], wenn du deinen Code mappst. Sie können dies selbst überprüfen, wenn Sie den Typ explizit in 'val f2: Future [Future [Int]] = ...' setzen – ameer