66 votes

Scala Futures - délai d'attente intégré ?

Il y a un aspect des futures que je ne comprends pas exactement à partir du tutoriel officiel réf. http://docs.scala-lang.org/overviews/core/futures.html

Les contrats à terme en Scala ont-ils un mécanisme de temporisation intégré ? Disons que l'exemple ci-dessous était un fichier texte de 5 gigaoctets... est-ce que la portée implicite de "Implicits.global" fait que onFailure se déclenche de manière non bloquante ou est-ce que cela peut être défini ? Et sans une sorte de délai d'attente par défaut, cela ne signifierait-il pas qu'il est possible que ni le succès ni l'échec ne se déclenchent jamais ?

import scala.concurrent._
import ExecutionContext.Implicits.global

val firstOccurence: Future[Int] = future {
  val source = scala.io.Source.fromFile("myText.txt")
  source.toSeq.indexOfSlice("myKeyword")
}
firstOccurence onSuccess {
  case idx => println("The keyword first appears at position: " + idx)
}
firstOccurence onFailure {
  case t => println("Could not process file: " + t.getMessage)
}

0 votes

Voir awaitAll

4 votes

Gardez à l'esprit qu'aucune de ces solutions n'arrêtera réellement l'épidémie. Future de la course. Le seul endroit où vous pouvez arrêter un Future est de l'intérieur.

1 votes

@NikitaVolkov Votre lien ne fonctionne plus. J'ai essayé de trouver le lien correct mais j'ai échoué.

0voto

PJ Fanning Points 629

J'utilise cette version (basée sur l'exemple Play ci-dessus) qui utilise le dispatcher du système Akka :

object TimeoutFuture {
  def apply[A](system: ActorSystem, timeout: FiniteDuration)(block: => A): Future[A] = {
    implicit val executionContext = system.dispatcher

    val prom = Promise[A]

    // timeout logic
    system.scheduler.scheduleOnce(timeout) {
      prom tryFailure new java.util.concurrent.TimeoutException
    }

    // business logic
    Future {
      try {
        prom success block
      } catch {
        case t: Throwable => prom tryFailure t
      }
    }

    prom.future
  }
}

0voto

sparker Points 621

Le moyen le plus simple de spécifier un délai d'attente pour les IMO futures est le mécanisme intégré de Scala, qui utilise les éléments suivants scala.concurrent.Await.ready Ceci lancera un TimeoutException si le futur prend plus de temps que le délai spécifié. Sinon, il renvoie le Future lui-même. Voici un exemple simple et artificiel

import scala.concurrent.ExecutionContext.Implicits._
import scala.concurrent.duration._
val f1: Future[Int] = Future {
  Thread.sleep(1100)
  5
}

val fDoesntTimeout: Future[Int] = Await.ready(f1, 2000 milliseconds)

val f: Future[Int] = Future {
  Thread.sleep(1100)
  5
}
val fTimesOut: Future[Int] = Await.ready(f, 100 milliseconds)

0voto

Smac89 Points 1926

Vous pouvez attendre qu'un futur se termine en utilisant la fonction Await .

import scala.concurrent.duration._
import scala.concurrent.{Await, Future}

val meaningOfLife: Int = Await.result(Future(42), 1.nano)
println (meaningOfLife)

Les impressions ci-dessus 42

Vous pouvez avoir besoin d'un ExecutionContext disponible, auquel cas, il suffit de l'ajouter :

import scala.concurrent.ExecutionContext.Implicits.global

Une autre façon de procéder est d'utiliser Coeval de monix . Cette méthode ne fonctionne pas dans toutes les situations, et vous pouvez tout lire à ce sujet aquí . L'idée de base est que parfois un futur ne prend pas vraiment de temps et renvoie le résultat d'un appel de fonction synchrone ou une valeur, ce futur peut donc être évalué sur le thread actuel. Cela est également utile pour tester et simuler les futurs. De plus, il n'est pas nécessaire de spécifier un délai d'attente, ce qui est attendu, mais c'est toujours agréable de ne pas avoir à s'en soucier.

Vous commencez par transformer le futur en un Task et envelopper cette tâche dans un Coeval puis croisez les doigts en attendant de voir ce que vous obtiendrez. Il s'agit d'un exemple très simple pour montrer comment cela fonctionne :

Vous avez besoin d'un Scheduler pour pouvoir l'utiliser :

import monix.execution.Scheduler.Implicits.global

Coeval(Task.fromFuture(Future (42)).runSyncStep).value() match {
   case Right(v) => println(v)
   case Left(task) => println("Task did not finish")
}

Ce qui précède complète et imprime 42 à la console.

Coeval(Task.fromFuture(Future {
   scala.concurrent.blocking {
      42
   }
}).runSyncStep).value() match {
   case Right(v) => println(v)
   case Left(task) => println("Task did not finish")
}

Cet exemple imprime Task did not finish :

0voto

Nikunj Kakadiya Points 126
You can simply run the future to completion without giving any timeout interval by setting the timeout to infinite as below:

**import scala.concurrent.duration._  
Await.result(run(executionContext), Duration.Inf)**

run function can be as below :

def run(implicit ec: ExecutionContext) = {  
      val list = Seq(  
          Future { println("start 1"); Thread.sleep(1000); println("stop 1")},  
          Future { println("start 2"); Thread.sleep(2000); println("stop 2")},  
          Future { println("start 3"); Thread.sleep(3000); println("stop 3")},  
          Future { println("start 4"); Thread.sleep(4000); println("stop 4")},  
          Future { println("start 5"); Thread.sleep(5000); println("stop 5")}  
      )  
      Future.sequence(list)  
    }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X