Zoeken…


Een toekomst creëren

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
    }
}

Heel eenvoudig, de divide creëert een toekomst die zal oplossen met het quotiënt van a over b .

Een succesvolle toekomst gebruiken

De eenvoudigste manier om een succesvolle Future-- consumeren of beter gezegd, krijgen de waarde in de Future-- is om het te gebruiken map methode. Stel dat sommige code roept de divide werkwijze van de FutureDivider object uit het "creëren van een toekomst" voorbeeld. Hoe zou de code eruit moeten zien om het quotiënt van a over b ?

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

Een mislukte toekomst gebruiken

Soms kan de berekening in een toekomst een uitzondering maken, waardoor de toekomst mislukt. Wat als in het voorbeeld "Een toekomst creëren" de belcode 55 en 0 divide aan de divide ? Het zou natuurlijk een ArithmeticException na proberen te delen door nul, natuurlijk. Hoe zou dat worden verwerkt in het consumeren van code? Er zijn eigenlijk een handvol manieren om met storingen om te gaan.

Behandel de uitzondering met recover en patroonovereenkomst.

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}")
        }
    }
}

Behandel de uitzondering met de failed projectie, waarbij de uitzondering de waarde van de toekomst wordt:

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}")
        }
    }
}

De toekomst samenbrengen

De vorige voorbeelden demonstreerden de individuele kenmerken van een toekomst, het afhandelen van succes- en faalgevallen. Meestal worden beide functies echter veel strenger behandeld. Hier is het voorbeeld, geschreven op een nettere en meer realistische manier:

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}")
        }
    }
}

Reeksen en doorlopen Futures

In sommige gevallen is het noodzakelijk om een variabel aantal waarden op afzonderlijke Futures te berekenen. Stel dat u een List[Future[Int]] , maar in plaats daarvan moet een List[Int] worden verwerkt. De vraag is dan hoe dit exemplaar van List[Future[Int]] in een Future[List[Int]] omgezet. Voor dit doel is er de sequence op het Future bijbehorende object.

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

In het algemeen is de sequence een algemeen bekende operator in de wereld van functioneel programmeren die F[G[T]] omzet in G[F[T]] met beperkingen voor F en G

Er is een alternatieve operator genaamd traverse , die vergelijkbaar werkt, maar een functie als extra argument neemt. Met de identiteitsfunctie x => x als parameter gedraagt deze zich als de sequence .

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

Het extra argument maakt het echter mogelijk om elke toekomstige instantie binnen de gegeven listOfFuture te wijzigen. Bovendien hoeft het eerste argument geen lijst van Future . Daarom is het mogelijk om het voorbeeld als volgt te transformeren:

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

In dit geval wordt de List(1,2,3) direct doorgegeven als eerste argument en wordt de identiteitsfunctie x => x vervangen door de functie Future(_) om op dezelfde manier elke Int waarde om te zetten in een Future . Een voordeel hiervan is dat de tussenliggende List[Future[Int]] kan worden weggelaten om de prestaties te verbeteren.

Combineer meerdere toekomsten - voor een beter begrip

Het begrip is een compacte manier om een codeblok uit te voeren dat afhankelijk is van het succesvolle resultaat van meerdere futures.

Met f1, f2, f3 drie Future[String] 's die respectievelijk de tekenreeksen one, two, three ,

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

fCombined wordt een Future[String] met de string one - two - three zodra alle futures met succes zijn voltooid.

Merk op dat hier een impliciete ExectionContext wordt verondersteld.

Houd er ook rekening mee dat voor begrip slechts een syntactische suiker is voor een flatMap-methode, zodat toekomstige objectenconstructie voor het lichaam de gelijktijdige uitvoering van codeblokken omsloten door futures zou elimineren en zou leiden tot opeenvolgende code. Je ziet het bijvoorbeeld:

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

Waarde ingesloten door result1 object zou altijd negatief zijn, terwijl result2 positief zou zijn.

Zie http://docs.scala-lang.org/tutorials/FAQ/yield.html voor meer informatie over begrip en yield in het algemeen.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow