Suche…


Zukunft gestalten

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

object FutureDivider {
    def divide(a: Int, b: Int): Future[Int] = Future {
        // Note that this is integer division.
        a / b
    }
}

Die divide Methode erzeugt ganz einfach eine Zukunft, die mit dem Quotienten von a über b .

Eine erfolgreiche Zukunft konsumieren

Der einfachste Weg , eine erfolgreiche Future-- oder eher zu konsumieren, um den Wert innerhalb des Future-- zu erhalten ist , die verwenden map Methode. Angenommen, ein Code ruft die divide Methode des FutureDivider Objekts aus dem Beispiel "Zukunft FutureDivider " auf. Wie müsste der Code aussehen, um den Quotienten von a über b ?

object Calculator {
    def calculateAndReport(a: Int, b: Int) = {
        val eventualQuotient = FutureDivider divide(a, b)
        
        eventualQuotient map {
            quotient => println(quotient)
        }
    }
}

Eine misslungene Zukunft konsumieren

Manchmal kann die Berechnung in einer Zukunft zu einer Ausnahme führen, wodurch die Zukunft scheitern kann. Was passiert, wenn der aufrufende Code in dem Beispiel "Zukunft erstellen" 55 und 0 an die divide Methode übergeben hat? Es würde natürlich eine ArithmeticException nachdem versucht wurde, durch Null zu teilen. Wie würde das mit verbrauchendem Code behandelt werden? Es gibt tatsächlich eine Reihe von Möglichkeiten, mit Fehlern umzugehen.

Behandeln Sie die Ausnahme mit recover und Pattern Matching.

object Calculator {
    def calculateAndReport(a: Int, b: Int) = {
        val eventualQuotient = FutureDivider divide(a, b)
    
        eventualQuotient recover {
            case ex: ArithmeticException => println(s"It failed with: ${ex.getMessage}")
        }
    }
}

Behandeln Sie die Ausnahme mit der failed Projektion, bei der die Ausnahme zum Wert der Zukunft wird:

object Calculator {
    def calculateAndReport(a: Int, b: Int) = {
        val eventualQuotient = FutureDivider divide(a, b)
    
        // Note the use of the dot operator to get the failed projection and map it.
        eventualQuotient.failed.map {
            ex => println(s"It failed with: ${ex.getMessage}")
        }
    }
}

Zukunft zusammenstellen

In den vorherigen Beispielen wurden die einzelnen Merkmale einer Zukunft sowie der Umgang mit Erfolg und Misserfolgen demonstriert. In der Regel werden jedoch beide Funktionen viel strenger behandelt. Hier ist das Beispiel, das auf eine schönere und realistischere Weise geschrieben wurde:

object Calculator {
    def calculateAndReport(a: Int, b: Int) = {
        val eventualQuotient = FutureDivider divide(a, b)
        
        eventualQuotient map {
            quotient => println(s"Quotient: $quotient")
        } recover {
            case ex: ArithmeticException => println(s"It failed with: ${ex.getMessage}")
        }
    }
}

Sequenzierung und Durchquerung von Futures

In einigen Fällen ist es erforderlich, eine variable Anzahl von Werten auf separaten Futures zu berechnen. Angenommen, Sie haben eine List[Future[Int]] , aber stattdessen muss eine List[Int] verarbeitet werden. Dann stellt sich die Frage, wie diese Instanz von List[Future[Int]] in eine Future[List[Int]] . Zu diesem Zweck gibt es die sequence im Begleitobjekt Future .

def listOfFuture: List[Future[Int]] = List(1,2,3).map(Future(_))
def futureOfList: Future[List[Int]] = Future.sequence(listOfFuture)

Im Allgemeinen ist sequence ein allgemein bekannter Operator in der Welt der funktionalen Programmierung, der F[G[T]] in G[F[T]] mit Einschränkungen auf F und G transformiert.

Es gibt einen alternativen Operator namens traverse , der ähnlich arbeitet, aber eine Funktion als zusätzliches Argument verwendet. Mit der Identitätsfunktion x => x als Parameter verhält es sich wie der sequence .

def listOfFuture: List[Future[Int]] = List(1,2,3).map(Future(_))
def futureOfList: Future[List[Int]] = Future.traverse(listOfFuture)(x => x)

Das zusätzliche Argument erlaubt es jedoch, jede zukünftige Instanz innerhalb der angegebenen listOfFuture zu ändern. Darüber hinaus muss das erste Argument keine Liste der Future . Daher ist es möglich, das Beispiel wie folgt umzuwandeln:

def futureOfList: Future[List[Int]] = Future.traverse(List(1,2,3))(Future(_))

In diesem Fall wird die List(1,2,3) direkt als erstes Argument übergeben und die Identitätsfunktion x => x wird durch die Funktion Future(_) , um jeden Int Wert auf ähnliche Weise in einen Future . Ein Vorteil davon ist, dass die Zwischenliste List[Future[Int]] weggelassen werden kann, um die Leistung zu verbessern.

Kombinieren Sie mehrere Futures - zum Verständnis

Das Verständnis ist eine kompakte Art, einen Codeblock auszuführen, der vom erfolgreichen Ergebnis mehrerer Futures abhängt.

Mit f1, f2, f3 drei Future[String] , die jeweils die Strings one, two, three enthalten.

val fCombined = 
    for {
        s1 <- f1
        s2 <- f2
        s3 <- f3
    } yield (s"$s1 - $s2 - $s3")

fCombined wird eine Future[String] die die Zeichenfolge one - two - three sobald alle Futures erfolgreich abgeschlossen wurden.

Beachten Sie, dass hier ein impliziter ExectionContext angenommen wird.

Denken Sie auch daran, dass das Verständnis nur ein syntaktischer Zucker für eine flatMap-Methode ist, sodass die Konstruktion zukünftiger Objekte für body die gleichzeitige Ausführung von von Futures umschlossenen Codeblöcken eliminiert und zu sequentiellem Code führt. Sie sehen es am Beispiel:

val result1 = for {
  first <- Future {
    Thread.sleep(2000)
    System.currentTimeMillis()
  }
  second <- Future {
    Thread.sleep(1000)
    System.currentTimeMillis()
  }
} yield first - second

val fut1 = Future {
  Thread.sleep(2000)
  System.currentTimeMillis()
}
val fut2 = Future {
  Thread.sleep(1000)
  System.currentTimeMillis()
}
val result2 = for {
  first <- fut1
  second <- fut2
} yield first - second

result1 Objekt result1 eingeschlossener result1 wäre immer negativ, während result2 positiv wäre.

Weitere Informationen zum Verständnis und zum yield im Allgemeinen finden Sie unter http://docs.scala-lang.org/tutorials/FAQ/yield.html



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow