2010-11-29 22 views
5

Soy nuevo en Scala en general y en Actores en particular y mi problema es muy básico, los recursos en línea que he encontrado no lo cubren.Usar actores para explotar núcleos

que tienen un algoritmo intensivo de la CPU, fácilmente parallelized que se ejecuta en una máquina de núcleo-n (no sé n). ¿Cómo implemento esto en Actores para que todos los núcleos disponibles resuelvan el problema?

La primera manera pensé era romper sencilla el problema en m piezas (donde m es algún número medio como 10000) y cree m Actores, uno para cada pieza, dé a cada Actor su poco pedazo y déjelos ir.

De alguna manera, esto me pareció ineficiente. Zillions de Actores simplemente dando vueltas, esperando algo de amor por CPU, contextos de cambio sin sentido ...

Entonces pensé, hacer un número más pequeño de Actores, y alimentar a cada uno varias piezas. El problema era que no hay ninguna razón para esperar que las piezas tengan el mismo tamaño, por lo que un núcleo podría atascarse, con muchas de sus tareas todavía en cola, mientras que otros núcleos están inactivos.

Estuve discutiendo con un supervisor que sabía qué actores estaban ocupados, y finalmente me di cuenta de que tenía que ser un problema resuelto. Debe haber un patrón estándar (tal vez incluso una biblioteca estándar) para tratar este problema tan genérico. ¿Alguna sugerencia?

Respuesta

8

Eche un vistazo a la biblioteca Akka, que incluye una implementación de actores. El Dispatchers Module le brinda más opciones para limitar los actores a los hilos de la CPU (basados ​​en eventos basados ​​en HawtDispatch) y/o equilibrar la carga de trabajo (basada en eventos de robo de trabajo).

3

Deberías tener en cuenta los futuros, creo. De hecho, es probable que necesite un subproceso de subprocesos que simplemente concatena subprocesos cuando se alcanza un número máximo de subprocesos.

Aquí hay un pequeño ejemplo que depende el futuro: http://blog.tackley.net/2010/01/scala-futures.html

También sugeriría que no presta demasiada atención al cambio de contexto ya que realmente no se puede hacer otra cosa que confiar en la implementación subyacente. Por supuesto, una regla empírica sería mantener los hilos activos alrededor de la cantidad de núcleos físicos, pero como señalé anteriormente, esto podría ser manejado por un threadpool con una fifo-queue.

TEN EN CUENTA que no sé si los actores en general o los futuros se implementan con este tipo de grupo.

Para grupos de subprocesos, mira esto: http://www.scala-lang.org/api/current/scala/concurrent/ThreadPoolRunner.html

y tal vez esto: http://www.scala-lang.org/api/current/scala/actors/scheduler/ResizableThreadPoolScheduler.html

Buena suerte

EDITAR

Echa un vistazo a este pedazo de código que utilizan los futuros:

import scala.actors.Futures._ 

object FibFut { 
    def fib(i: Int): Int = if (i < 2) 1 else fib(i - 1) + fib(i - 2) 
    def main(args: Array[String]) { 
    val fibs = for (i <- 0 to 42) yield future { fib(i) } 
    for (future <- fibs) println(future()) 
    } 
} 

Muestra un muy buen punto sobre futuros, es decir que usted decide en qué orden recibir los resultados (a diferencia del sistema de buzón normal que emplea un fifo-sistema, es decir, el actor más rápido envía su resultado primero).

0

Para cualquier proyecto importante, generalmente tengo un actor supervisor, una colección de actores trabajadores cada uno de los cuales puede hacer cualquier trabajo necesario, y una gran cantidad de trabajos para hacer. Aunque hago esto bastante a menudo, nunca lo puse en una biblioteca (personal) porque las operaciones terminan siendo tan diferentes cada vez, y la sobrecarga es bastante pequeña en comparación con todo el proyecto de codificación.

3

Generalmente, hay 2 tipos de actores: los que están vinculados a hilos (un hilo por actor) y los que comparten hilo 1+, que trabajan detrás de un planificador/despachador que asigna recursos (= posibilidad de ejecutar un tarea/manejar el mensaje entrante contra el grupo de hilos controlado o un solo hilo).

Supongo que utilizas el segundo tipo de actores, actores impulsados ​​por eventos, porque mencionas que ejecutas 10k de ellos. No importa cuántos actores controlados por eventos tengas (miles o millones), todos ellos lucharán por el pequeño grupo de subprocesos para manejar el mensaje. Por lo tanto, incluso tendrá un peor rendimiento dividiendo su cola de tareas en una gran cantidad de porciones: el planificador tratará de manejar los mensajes enviados a 10k actores contra un grupo de subprocesos fijos (que es lento), o asignará nuevos subprocesos en el grupo (si el grupo no está limitado), lo cual es peligroso (en el peor de los casos, se iniciarán los hilos de 10k para manejar los mensajes).

Los actores controlados por eventos son buenos para tareas de corta duración (idealmente, sin bloqueo). Si está trabajando con tareas intensivas en CPU, limitaría el número de subprocesos en el grupo de planificador/despachador (cuando usa actores guiados por eventos) o los propios actores (cuando usa actores basados ​​en subprocesos) en la cantidad de núcleos para lograr el mejor rendimiento

Si quieres que esto se haga de forma automática (ajustar el número de procesos en la piscina despachador para el número de núcleos), se debe utilizar HawtDisaptch (o no lo Akka implementation), tal como se propuso anteriormente:

El 'HawtDispatcher' utiliza la biblioteca de subprocesos HawtDispatch que es un clon de Java de libdispatch. Todos los actores con este tipo de despachador se ejecutan en un solo conjunto de subprocesos de tamaño fijo de un solo sistema. El número de hilos de coincidirá con la cantidad de núcleos disponibles en su sistema. El despachador envía mensajes a los actores en el orden en que fueron productor en el remitente.

0

Be aware of actor starvation si termina utilizando el hilo general actor. Terminé simplemente usando mi propio threadpool propiedad de la tarea algorithm para manejar la paralelización de una tarea concurrente de larga ejecución.

0

Se espera que el próximo Scala 2.9 incluya estructuras de datos paralelas que deberían manejar esto automáticamente para algunos usos. Si bien no utiliza Actores, puede ser algo a considerar para su problema.

Si bien esta característica se programó originalmente para 2.8, se ha pospuesto hasta la próxima versión principal.

Una presentación de los últimos ScalaDays está aquí:

http://days2010.scala-lang.org/node/138/140