2012-03-05 14 views
21

Implementé un sistema Actor usando Akka y su API Java UntypedActor. En él, un actor (tipo A) inicia dinámicamente a otros actores (tipo B) bajo demanda, usando getContext().actorOf(...);. Esos actores B harán algunos cálculos que a A ya no le importan realmente. Pero me pregunto: ¿es necesario limpiar a los actores de tipo B cuando hayan terminado? ¿Si es así, cómo?Akka: ¿Es necesaria la limpieza de los actores creados dinámicamente cuando hayan terminado?

  • Al tener actores B, ¿llamen al getContext().stop(getSelf()) cuando hayan terminado?
  • Al tener actores B, ¿llamen al getSelf().tell(Actors.poisonPill()); cuando hayan terminado? [esto es lo que estoy usando ahora].
  • Al hacer nada?
  • Por ...?

Los documentos no son claros en esto, o lo he pasado por alto. Tengo algunos conocimientos básicos de Scala, pero las fuentes de Akka no son exactamente de nivel de entrada ...

Respuesta

23

Lo que está describiendo son actores de propósito único creados por "solicitud" (definidos en el contexto de A), que manejan una secuencia de eventos y luego se completan, ¿no? Eso está absolutamente bien, y tiene razón en cerrarlos: si no lo hace, se acumularán con el tiempo y se encontrará con una pérdida de memoria. La mejor forma de hacerlo es la primera de las posibilidades que mencionas (la más directa), pero la segunda también está bien.

Un poco de antecedentes: los actores están registrados dentro de sus padres para ser identificables (por ejemplo, se necesitan en lugares remotos pero también en otros lugares) y este registro evita que sean basura. OTOH, cada padre tiene derecho a acceder a los hijos que creó, por lo tanto, no tiene sentido la terminación automática (es decir, por Akka), sino que requiere el cierre explícito del código de usuario.

+0

http: // stackoverflow.com/questions/23066264/can-wrapping-akka-actors-in-class-actors-caused-memory-leaks <- Pregunta relacionada –

-3

Los actores de forma predeterminada no consumen mucha memoria. Si la aplicación tiene la intención de utilizar el actor b más adelante, puede mantenerlos vivos. Si no, puedes cerrarlos a través de poisonpill. Mientras sus actores no tengan recursos, dejar a un actor debería estar bien.

+4

Pero, como señaló Roland, los actores no serán recogidos basura y por lo tanto se acumularán con el tiempo => pérdida de memoria. –

0

Además de la respuesta de Roland Kuhn, en lugar de crear un nuevo actor para cada solicitud, puede crear un conjunto predefinido de actores que comparten el mismo despachador o puede usar un enrutador que distribuye solicitudes a un grupo de actores.

El Balancing Pool Router, por ejemplo, le permite tener un conjunto fijo de actores de una acción tipo particular del mismo buzón:

akka.actor.deployment { 
    /parent/router9 { 
    router = balancing-pool 
    nr-of-instances = 5 
    } 
} 

leer la documentación sobre dispatchers y en routing para más detalles.

0

Estaba perfilando (visualvm) una de las aplicaciones de clúster de muestra de la documentación de AKKA y veo que la recolección de basura limpia los agentes por solicitud durante cada GC. No se puede comprender completamente la recomendación de matar explícitamente al actor después de su uso. Mi sistema de actores y actores son manejados por SPRING IOC container y utilizo la extensión de primavera en directo actor-productor para crear actores. El actor "agregador" está recibiendo basura recolectada en cada GC, sí controlé el número de instancias en VM visual.

@Component 
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 
public class StatsService extends AbstractActor { 

    private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this); 

    @Autowired 
    private ActorSystem actorSystem; 

    private ActorRef workerRouter; 

    @Override 
    public void preStart() throws Exception { 
     System.out.println("Creating Router" + this.getClass().getCanonicalName()); 
     workerRouter = getContext().actorOf(SPRING_PRO.get(actorSystem) 
      .props("statsWorker").withRouter(new FromConfig()), "workerRouter"); 
     super.preStart(); 
    } 

    @Override 
    public Receive createReceive() { 
     return receiveBuilder() 
      .match(StatsJob.class, job -> !job.getText().isEmpty(), job -> { 
       final String[] words = job.getText().split(" "); 
       final ActorRef replyTo = sender(); 
       final ActorRef aggregator = getContext().actorOf(SPRING_PRO.get(actorSystem) 
        .props("statsAggregator", words.length, replyTo)); 

       for (final String word : words) { 
        workerRouter.tell(new ConsistentHashableEnvelope(word, word), 
         aggregator); 
       } 
      }) 
      .build(); 
    } 
} 
Cuestiones relacionadas