2012-09-13 18 views
6

Me dijeron que los actores (Scala) nunca realizan dos operaciones al mismo tiempo, lo que sugiere que el método act (o reaccionar? O recibir?) Está inherentemente sincronizado. Sé que una operación larga en un método act puede causar problemas de bloqueo, y supongo que el acceso a la cola de mensajes debe estar sincronizado de alguna manera ... pero ...comprensión del enhebrado de los actores en scala

Lo que se sugirió es que un actor reciba mensajes reveladores incrementar un contador interno incrementaría el contador de una manera segura para el hilo. Que no se procesarán dos mensajes de actualización simultáneamente, por lo que no hay dos mensajes que intenten actualizar el contador al mismo tiempo.

Un atributo de contador en un actor suena como "estado compartido".

¿Es realmente cierto que una operación así sería completamente segura para los hilos? Si es así, ¿cómo hace un actor para usar máquinas centrales múltiples de alguna manera eficiente? ¿Cómo es un actor multi enhebrado en absoluto?

Si no es así, ¿cuál es una forma idiomática apropiada para contar mensajes de forma segura sin necesidad de alguna variable sincronizada/volátil?

Respuesta

8

El modelo actores pueden usarse para aislar estado mutable del mundo exterior. Cuando tiene un estado mutable (por ejemplo, un registro global de identificadores asignados a múltiples procesos concurrentes), puede ajustar ese estado mutable dentro de un Actor y hacer que los clientes se comuniquen con el Actor mediante el envío de mensajes. De esta forma, solo el actor accede al estado mutable directamente, y como dices, los mensajes del cliente hacen cola para leerse y procesarse uno por uno. Es importante que los mensajes sean inmutables.

Para evitar que la cola se llene, es importante que el procesamiento del mensaje (react, receive, etc.) sea lo más breve posible.tareas que se ejecutan largos deben ser entregados fuera a otro agente:

1. Actor A receives a message M from sender S 
2. A spawns a new actor C 
3. A sends (S, f(M)) to C 
4. In parallel: 
4a. A starts processing the next message. 
4b. C does the long-running or dangerous (IO) task, 
    When finished, sends the result to S, 
    and C terminates. 

Algunas alternativas en el proceso:

  • C envía (S, result) vuelta a A, que reenvía a S
  • A mantiene un mapeo ActorRef C => (Sender S, Message M)so in case it sees C fail, puede reintentar procesar M con un nuevo Actor.

Así que para recapitular, un actor es multi-hilo en la medida en que varios clientes pueden enviar múltiples mensajes de varios hilos, y se garantiza que el actor procesará todos estos mensajes en serie (aunque el pedido puede ser sujeto a varias restricciones no excesivamente estrictas).

Tenga en cuenta que mientras el Actor react código may be executed on various threads, en un único punto de tiempo dado se ejecuta en un solo hilo dado solamente (puede imaginarse que el Actor salta de hilo a hilo como el planificador lo considere adecuado, pero esto es un detalle técnico). Nota: El estado interno aún no necesita sincronización, ya que los actores guarantee happens-before semantics entre mensajes de procesamiento.

El paralelismo se logra teniendo varios actores trabajando en paralelo, generalmente formando supervisor hierarchies o balancing workload.

Tenga en cuenta que si todo lo que necesita son cálculos concurrentes/asincrónicos, pero no tiene o puede deshacerse del estado global, Futures are a better composing y el concepto es más fácil.

+0

¡Esta es una gran explicación, gracias! – Brian

+0

Buena respuesta. Yo agregaría que si bien las reacciones de un actor pueden ejecutarse en diferentes hilos (y por lo tanto 'normalmente' estarían sujetas a problemas de acceso a la memoria), en realidad no necesita sincronizar el acceso al estado del actor. Esto se debe a que el marco del actor ya lo hace antes de ejecutar un actor. Ver http://stackoverflow.com/questions/1031167/should-my-scala-actors-properties-be-marked-volatile –

+0

Me alegro de que ayude. Régis: Gracias, actualizó el texto para ser más preciso. – ron

6

"Un actor" no es multiproceso, pero un sistema de actor suele ser. Cada actor ejecuta solo una acción a la vez, pero cuando hay múltiples actores, cada uno puede operar en su respectivo estado encapsulado en paralelo. Un contador de atributo no es compartido estado mutable si no se comparte entre los actores.

Si su pregunta es acerca de la implementación del sistema actor, eso varía y generalmente es configurable, es decir, los actores predeterminados de Scala se pueden configurar para ejecutar un solo subproceso o en un grupo de subprocesos o utilizar tareas de Java ForkJoin. Encuentro que la fuente scala.actors es muy legible, por lo que recomiendo echar un vistazo si quieres entender qué está pasando.

+0

+1 para el puntero al código fuente de Scala. Muestra muy bien el concepto. – sourcedelica

2

Puede usar un actor por separado para hacer el recuento. Cuando un actor recibe un mensaje, puede disparar un mensaje a un actor de conteo (singleton). De esta forma, podría tener múltiples actores trabajadores y aún contar mensajes.

Akka tiene algo llamado Agents que podría ser útil en este contexto.

val counter = Agent(0) 
counter send (_ + 1) 

http://doc.akka.io/docs/akka/2.0.2/scala/agents.html

+0

Un agente está hecho a medida para este caso de uso. En términos de enhebrado y sincronización, funcionan como actores para escrituras y AtomicX para lecturas. – sourcedelica

Cuestiones relacionadas