Подтвердить что ты не робот

Акка: Очистка динамически созданных актеров необходима, когда они закончили?

Я реализовал систему Actor с использованием Akka и Java API UntypedActor. В нем один актер (тип A) запускает другие участники (тип B) динамически по требованию, используя getContext().actorOf(...);. Те B-актеры будут делать некоторые вычисления, которые A на самом деле не волнует больше. Но мне интересно: нужно ли очищать тех актеров типа B, когда они закончили? Если да, то как?

  • Когда участники B вызывают getContext().stop(getSelf()), когда они закончены?
  • Когда участники B вызывают getSelf().tell(Actors.poisonPill());, когда они закончатся? [это то, что я сейчас использую].
  • Ничего не делая?
  • По...?

Документы не ясны по этому поводу, или я не обратил на это внимания. У меня есть некоторые базовые знания Scala, но источники Akka - это не совсем вещи начального уровня...

4b9b3361

Ответ 1

То, что вы описываете, - это одноцелевые актеры, созданные за "запрос" (определенные в контексте A), которые обрабатывают последовательность событий, а затем выполняются, правильно? Это абсолютно нормально, и вы правы закрыть их: если вы этого не сделаете, они будут накапливаться с течением времени, и вы столкнетесь с утечкой памяти. Лучший способ сделать это - это первая из возможностей, которые вы упомянули (самая прямая), но вторая тоже хорошо.

Немного фона: актеры регистрируются в их родителях, чтобы быть идентифицируемыми (например, необходимыми в удалении, но также и в других местах), и эта регистрация не позволяет им собирать мусор. OTOH, каждый родитель имеет право доступа к созданным им детям, поэтому автоматическое завершение (то есть Akka) не имеет смысла, вместо этого требуется явное закрытие кода пользователя.

Ответ 2

В дополнение к ответу Роланда Куна вместо создания нового актера для каждого запроса вы можете создать предопределенный набор участников, которые используют один и тот же диспетчер, или вы можете использовать маршрутизатор, который распространяет запросы в пул участников.

"Балансирующий пул маршрутизатора" , например, позволяет вам иметь фиксированный набор участников определенного типа совместно использовать один и тот же почтовый ящик:

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

Прочитайте документацию по dispatchers и routing для более подробной информации.

Ответ 3

Я профилировал (visualvm) одно из примеров кластерного приложения из документации AKKA, и я вижу уборку мусора для каждого участника запроса во время каждого GC. Невозможно полностью понять рекомендацию явно убить актера после использования. Моя актерская система и актеры управляются контейнером IOC SPRING, и я использую расширение SPRING для прямого актера-продюсера для создания актеров. Актер " агрегатор" получает мусор, собранный на каждом GC, я контролировал # экземпляров в визуальной VM.

@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();
    }
}

Ответ 4

Актеры по умолчанию не потребляют много памяти. Если приложение намерено использовать актер b позже, вы можете сохранить их в живых. Если нет, вы можете закрыть их через яд. До тех пор, пока ваши актеры не будут располагать ресурсами, оставив актера в порядке.