Leyendo el futuro en Scala

Hoy explotaremos nuestras habilidades místicas para intentar adivinar el futuro. Para ello, utilizaremos el tipo Future que nos proporciona Scala.

a7cae161ea16b893de40b46acadedad9b57373e6ebacfe9cd4bb57a32686517a

Espera, espera, ¿qué es el tipo Future?

El tipo Future en Scala se utiliza para computar operaciones costosas en segundo plano sin que se bloquee el hilo de ejecución principal. En dicho Future, se generará el resultado de una o más operaciones. Para ello, se lanzará un thread paralelo.
Por ejemplo, si nos levantamos un día con la necesidad de saber cuales son los mil primeros números primos, deberíamos hacerlo así:


def getFirstMillionOfPrimes: List[Int] = ???

val f: Future[List[Int]] = Future{ getFirstMillionOfPrimes }

Una vez que el resultado del Futuro se ha calculado, se puede obtener dicho resultado principalmente de dos formas distintas:

  • De forma bloqueante: bloqueando la ejecución hasta que el futuro se haya completado.
  • De forma no bloqueante: dejando pendiente la ejecución de una función que se ejecutará cuando el futuro se haya completado. Vamos, un callback de toda la vida.

Vamos a ver como se realizaría.

Modo vidente de pacotilla

Una de las opciones es realizar una llamada bloqueante sobre el futuro. Esta llamada bloqueante esperará hasta que el futuro se haya completado, y una vez completado devolverá su resultado.

Para ello se utiliza la llamada Await.result:


val f: Future[Int] = Future{
  Thread.sleep(10000)
  2
}

println(Await.result(f,12.seconds))  //2

Como se puede ver, es necesario definir un timeout para no esperar indefinidamente. En caso de que el Future tarde más en computar el resultado que el timeout definido, saltará una excepción de timeout.

Esta forma de obtener el resultado no es recomendable ya que al bloquear la ejecución del programa, estamos realizando justo lo que se pretende evitar utilizando el tipo Future. Sin embargo, en algunas ocaciones se utiliza, por ejemplo, a la hora de realizar testing.

Modo vidente auténtico (con título acreditativo) 

¿Y entonces cómo debemos trabajar con los Future? Pues muy sencillo, mediante callbacks.

Los callbacks nos permitirán realizar una o varias acciones una vez que se resuelva el futuro. Pero, y aquí está la magia, lo hará de forma no bloqueante. El callback se definirá y será llamado de forma transparente cuando el futuro se complete. Mientras tanto, el programa seguirá su ejecución.

Para  tratar el resultado se utilizarán los tipos Success y Failure. Esto es debido a que se utilizará un Try para intentar obtener el valor del futuro. Ya comentamos este tipo en otro post, pero vamos a ver como aplicaría a los futuros:

  • Si el futuro ha conseguido calcular con éxito su cometido, se devuelve el resultado encapsulado en un tipo Success.
  • En caso contrario, si algo ha ido mal, se devolverá la excepción producida envuelta en un tipo Failure.

crystal-ball-failure_300px

¿Y cómo se define un callback? Pues muy sencillo:


f.onComplete( (t: Try[Int]) => println(t) )
//Success(2)

En este caso, esperamos a que se complete el futuro que había definido previamente, e imprimimos su resultado. Como hemos visto, dicho resultado estará encapsulado en un tipo Try.

Además, podemos definir callbacks que solo se ejecutarán si el futuro ha ido bien o si el futuro ha ido mal:


f.onSuccess( n => println(n) )
//2

f.onFailure( throwable => println(throwable.getMessage) )
//it will never print an error (because it equals Success(2))

Esto de los callbacks está muy bien. Sin embargo, una de las operaciones más usadas contra el tipo Future son las transformaciones. Mediante estas transformaciones, podremos cambiar el resultado del Futuro sin esperar explícitamente a que se obtenga el valor computado. Pero, debido a la gran cantidad de transformaciones que se pueden aplicar a un futuro, creo que ese tema merece su propio post dedicado. Así que, nada más por hoy. Hasta otra! 🙂

 

Anuncios

3 thoughts on “Leyendo el futuro en Scala

  1. muy guay el post, ahora a esperar el siguiente 😉 para ver formas idiomáticas de trabajar con esto

    Intuyo que el ‘onComplete’ puede darte tanto un Success(x) como un Failure(error), no? en ese caso habría que tirar de pattern matching?

    Me gusta

    • Muchas gracias por tu feedback 🙂

      Efectivamente, en el método onComplete se trabaja directamente con el tipo Try. Dicho tipo Try será, o bien un Success, o bien un Failure. Y, por supuesto, dicho Try se podría evaluar mediante Pattern Matching.

      Un saludo!

      Me gusta

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s