2009-10-06 9 views
8

Después de leer sobre el uso de react en los actores de Scala, pensé que react compartiría el mismo hilo dado que no había múltiples react pendientes. No parece ser el caso.¿Cuándo se crean los hilos para las reacciones de Scala actor?

import scala.actors.Actor 
import scala.actors.Actor._ 

class SleepyReactor extends Actor { 
    def act() { 
     loop { 
      react { 
       case x => { 
        println("reacting to %s on thread %s".format(x, Thread.currentThread.getName)) 
        Thread.sleep(1000) 
        println("done with " + x) 
       } 
      } 
     } 
    } 
} 
val sleepyOne = new SleepyReactor 
sleepyOne.start 
sleepyOne ! "first" // runs on thread-5 

// wait until completion 

sleepyOne ! "second" // runs on thread-3 

¿Puede alguien explicar por qué estos react 's se ejecutan en diferentes hilos y cuando se crea un nuevo hilo para un actor con react?

He leído en algún lugar react basado en eventos, y lo tomé como que los "actores reaccionan" compartían un hilo y si uno estaba "reaccionando" los otros "actores reactivos" se pondrían en cola hasta que terminara el primero. Ahora pienso que estoy equivocado. ¿Cómo funciona esto, y cómo es diferente de recibir?

+0

ver también http://stackoverflow.com/questions/1251666/scala- actores-recibir-contra-reaccionar –

Respuesta

9

Es cierto que para un actor puro basado en eventos, su código de reacción se ejecuta en el mismo hilo que el código de envío de mensajes.

Pero en Scala, ya que no es conveniente bloquear un hilo cuando un actor llama a una operación de bloqueo dentro de su código de reacción y unificar actores basados ​​en eventos y en hilos (pudiendo componerlos), ambos tipos de actores utiliza el mismo grupo de subprocesos pero los actores basados ​​en subprocesos obtienen sus propios subprocesos mientras que los actores basados ​​en eventos comparten subprocesos basados ​​en una cola de tareas. Para obtener más información, consulte Actors that Unify Threads and Events por Philipp Haller y Martin Odersky

3

La biblioteca del planificador utiliza un grupo de subprocesos para controlar la ejecución de los actores. No sé los detalles de la lógica que utiliza, pero, para mí, parece natural esperar que:

  • Inicializar con más de un hilo en la piscina, ya que las aplicaciones multitarea, es muy probable para usar más de un thead.

  • Seleccione el hilo que se utilizará con un actor en espera en forma de cola: los hilos se liberan hasta el final de la cola y se adquieren desde el principio de la cola.

Además, supongo que algunos subprocesos se utilizan para gestionar la programación y la transmisión de mensajes.

5

No asuma un hilo por cada Actor. La maquinaria Scala crea un grupo de subprocesos de trabajo y solo crece ese grupo si el tamaño de Actores bloqueados es mayor que el tamaño del grupo. Cuando su actor llama al receive, está bloqueado hasta que recibe su mensaje.

4

Para ver el efecto descrito en las respuestas anteriores, debe generar más de dos subprocesos. Este programa de ejemplo genera 100 hilos con recepción y 100 hilos con reacción.

Cuando lo ejecuta, puede ver que cada uno de los actores receptores ocupa un hilo, y los que reaccionan comparten un pequeño número de hilos. (Es más fácil de ver cuando se ordena la salida.)

import scala.actors._ 
import scala.actors.Actor._ 

class ReactActor extends Actor { 
    def act { 
    loop { 
     react { 
     case 'Hello => println("React: " + Thread.currentThread) 
     } 
    } 
    } 
} 

class ReceiveActor extends Actor { 
    def act { 
    while (true) { 
     receive { 
     case 'Hello => println("Receive: " + Thread.currentThread) 
     } 
    } 
    } 
} 

object Main { 
    def main(args: Array[String]) { 
    val count = 100 
    val as = new Array[Actor](2 * count) 
    for (i <- 0 until count) { 
     as(i) = new ReactActor 
     as(count + i) = new ReceiveActor 
    } 
    for (a <- as) a.start() 
    actor { 
     println(Thread.currentThread) 
     for (a <- as) a ! 'Hello 
    } 
    } 
} 

La salida ordenada en un típico proceso del programa:

Thread[Thread-102,5,main] 
React: Thread[Thread-102,5,main] 
React: Thread[Thread-102,5,main] 
React: Thread[Thread-102,5,main] 
... 
React: Thread[Thread-102,5,main] 
React: Thread[Thread-103,5,main] 
React: Thread[Thread-103,5,main] 
... 
React: Thread[Thread-103,5,main] 
React: Thread[Thread-104,5,main] 
React: Thread[Thread-104,5,main] 
React: Thread[Thread-104,5,main] 
... 
React: Thread[Thread-104,5,main] 
React: Thread[Thread-105,5,main] 
React: Thread[Thread-105,5,main] 
React: Thread[Thread-105,5,main] 
... 
React: Thread[Thread-105,5,main] 
Receive: Thread[Thread-1,5,main] 
Receive: Thread[Thread-10,5,main] 
Receive: Thread[Thread-100,5,main] 
Receive: Thread[Thread-101,5,main] 
Receive: Thread[Thread-11,5,main] 
Receive: Thread[Thread-12,5,main] 
Receive: Thread[Thread-13,5,main] 
Receive: Thread[Thread-14,5,main] 
Receive: Thread[Thread-15,5,main] 
Receive: Thread[Thread-16,5,main] 
Receive: Thread[Thread-17,5,main] 
Receive: Thread[Thread-18,5,main] 
Receive: Thread[Thread-19,5,main] 
Receive: Thread[Thread-2,5,main] 
Receive: Thread[Thread-20,5,main] 
Receive: Thread[Thread-21,5,main] 
... 
Cuestiones relacionadas