2012-05-12 35 views
9

Estaba intentando reproducir el ejemplo en el nuevo Scala 2.10 futures feature. El código que he usado es:Posible error en Scala 2.10: los futuros no se ejecutan

import scala.concurrent.Future 
import scala.concurrent.future 

object Test { 
    def main(args: Array[String]) { 
    println("Test print before future") 
    val s = "Hello" 
    val f = future {s + " future!"} 
    f onSuccess {case v => println(v)} 
    println("Test print after future") 
    } 
} 

En lugar de imprimir:

Test print before future 
Hello future! 
Test print after future 

simplemente imprime:

Test print before future 
Test print after future 

Cualquier idea de por qué tengo este comportamiento? Mi versión del compilador scala es 2.10.0-20120507.

Respuesta

28

La cuestión es que se está ejecutando que como un programa independiente, cuyo principal el subproceso finaliza antes de que uno de los subprocesos de trabajo pueda ejecutar el "¡Hola, futuro!" println. (Los hilos que genera la nueva biblioteca de futuros son hilos de daemon).

También se puede utilizar el objeto Await (también en scala.concurrent) que esperar hasta que se complete el futuro f:

import scala.concurrent._ 
import scala.concurrent.util._ 

object Test { 
    def main(args: Array[String]) { 
    println("Test print before future") 

    val s = "Hello" 
    val f = future {s + " future!"} 
    f onSuccess {case v => println(v)} 
    println("Test print after future") 

    Await.ready(f, Duration.Inf) 
    } 
} 

Esto puede imprimir:

Test print before future 
Test print after future 
Hello future! 

O bien, se puede imprimir "Hola ¡futuro!" antes de "Prueba de impresión después del futuro", según el programa del hilo.

Del mismo modo, se puede forzar el hilo principal que esperar hasta f se completa antes de la última println de la siguiente manera:

import scala.concurrent._ 
import scala.concurrent.util._ 

object Test { 
    def main(args: Array[String]) { 
    println("Test print before future") 

    val s = "Hello" 
    val f = future {s + " future!"} 
    f onSuccess {case v => println(v)} 

    Await.ready(f, Duration.Inf)   

    println("Test print after future") 
    } 
} 

Cuál sería imprimir:

Test print before future 
Hello future! 
Test print after future 

Sin embargo, tenga en cuenta que cuando se utiliza Await, estás bloqueando. Esto, por supuesto, tiene sentido para asegurarse de que el hilo de la aplicación principal no finaliza, pero en general no debe usarse a menos que sea necesario.

(El objeto Await es una puerta de escape necesaria para situaciones como estas, pero usarlo en todo el código de la aplicación sin preocuparse por su semántica puede dar como resultado una ejecución más lenta y menos paralela. orden especificado, por ejemplo, hay otras alternativas, como los métodos andThen y map en Future.)

+0

¿Sabes? Pensé en esto porque es exactamente de la misma manera cuando trabajas con goroutines: usas canales para esperar un mensaje enviado por los goroutines antes de cerrar el bloque principal. –

+0

@Heather ¿Es posible esperar más de un futuro? – 66CLSjY

1

Creo que el problema aquí es el tiempo. Lo más probable es que su código futuro se ejecute en un hilo deamon separado. Creo que la aplicación termina muy rápido y este subproceso deamon no tiene tiempo suficiente para ejecutarse correctamente (la aplicación no espera a que termine el hilo deamon). Pero esto también es un comportamiento muy dependiente del sistema. Para mí imprime:

Test print before future 
Test print after future 
Hello future! 

y luego sale (estoy usando Scala 2.10.0-M3). Puede seguir los siguientes pasos para probarlo - sólo hay que poner hilo principal de ejecución en el sueño durante varios segundos y ver si se imprime Hello future!:

import scala.concurrent.Future 
import scala.concurrent.future 

object Test { 
    def main(args: Array[String]) { 
     println("Test print before future") 

     val s = "Hello" 
     val f = future {s + " future!"} 
     f onSuccess {case v => println(v)} 

     println("Test print after future") 

     Thread.sleep(3000) 
     println("Test print at the end.") 
    } 
} 
1

Solo quiero agregar que, en general, existe otra posibilidad de que los futuros no se estén ejecutando: alcanzar el límite del grupo de subprocesos.

En su caso, probablemente era simplemente un problema de tiempo como otros han señalado, sino como referencia en el futuro Considere este ejemplo:

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


object FutureDebug { 
    def main(args: Array[String]) { 

    for (i <- Range(0, 4)) { 
     future { 
     while (true) { 
      Thread.sleep(1000) 
      println("I'm doing stupid things in a future") 
     } 
     } 
    } 

    println("(1) reached? yes") 
    val fut = future { 
     for (i <- Range(0, 1000)) { 
     println("never reached " + i) 
     } 
     3.14 
    }  
    println("(2) reached? yes") 
    Await.result(fut, Duration.Inf) 
    println("(3) reached? no") 
    } 
} 

En mi máquina el contexto global de ejecución por defecto tiene sólo 4 hilos. Como los hilos de trabajo están ocupados ejecutando los 4 futuros sin sentido, el futuro siguiente nunca se ejecutará. Esta es la razón por la que se debe tener cuidado con el contexto de ejecución predeterminado y es mejor que specify one's own execution context cuando se trate de futuros múltiples (realmente) largos.

Cuestiones relacionadas