1) Является ли erlang: send_after в init хорошим решением?
номер
Какова лучшая практика, если мне нужно, чтобы процесс начал выполнять работу немедленно, она была порождена, не вызывая его функции извне?
См. здесь . Установите таймаут 0, а затем выполните:
handle_info(timeout, State) ->
whatever_you_wish_to_do_as soon_as_server_starts,
{noreply, State}.
Нулевой тайм-аут означает, что сервер отправит себе информацию «тайм-аут», как только завершит инициализацию, перед обработкой любого другого вызова / приведения.
Также см. модуль таймера . Вместо рекурсивного вызова send_after в handle_info (do_ping, State), просто запустите таймер и скажите ему отправлять вам «do_ping» каждые? PING_INTERVAL.
2) В настоящее время я запускаю ping с помощью pinger: ping ("127.0.0.1"). команда. Модуль pinger попросит pinger_sup запустить дочерний процесс. После того, как процесс был запущен, я хочу остановить его. Каков предпочтительный способ сделать это? Должен ли я прекратить его с помощью sup или отправить ему команду остановки?
Вы должны отправить ему команду остановки. Зачем убивать gen_server с помощью супервизора, если gen_server может сделать это сам? : -)
Как хранить PID процесса? В настоящее время я использую словарь процессов, но после его реализации я понял, что словарь на самом деле не принадлежит к sup (это словарь оболочки или любой другой вызывающий объект stop_child). В случае, если я использую ETS и sup отключается, будут ли эти мертвые PID процесса оставаться в ETS навсегда, вызывая утечку памяти?
Таблицы ETS уничтожаются, как только завершается процесс владельца. Так что утечки памяти нет.
Но хранить PID так, как вы это делаете, - не «путь Эрланга». Вместо этого я предлагаю сделать дерево супервизора. Вместо того, чтобы ставить всех работников pinger под pinger_sup и затем вспоминать, какой работник пингует с какого IP, я предлагаю, чтобы pinger_sup запускал supervisor , который обрабатывает данный IP. И тогда этот начальник начинает необходимое количество рабочих.
Теперь, когда вы хотите прекратить пинговать какой-нибудь IP, вы просто убиваете супервизора за этот IP, и он автоматически убивает своих детей.
И как бы вы узнали, какой руководитель имеет дело с каким IP? Ну, поместите IP в имя супервизора :-) При создании супервизора, который имеет дело с IP, сделайте что-то вроде этого:
-module(pinger_ip_sup).
start_link(Ip) ->
supervisor:start_link({global, {?MODULE, Ip}}, ?MODULE, []).
Затем, когда вы хотите прекратить пинговать Ip, вы просто убиваете супервизора по имени {global, {pinger_ip_sup, Ip}}, и он убивает своих детей: -)
редактировать относительно комментариев:
Если вы хотите обработать ошибку, которая приводит к тайм-аутам, вы можете зарезервировать переменную состояния, которая сообщит вам, истек ли тайм-аут, вызванный init, или тайм-аут, вызванный ошибкой. Например:
-record(pinger_state, {ip, initialized}).
init(Ip) ->
State = #pinger_state{ip = Ip, initialized = false}.
{ok, State, 0}.
handle_info(timeout, State#pinger_state{initialized = false}) ->
whatever_you_wish_to_do_as soon_as_server_starts,
New_state = State#pinger_state{initialized = true}.
{noreply, New_state}.
handle_info(timeout, State#pinger_state{initialized = true}) ->
error_handling,
{noreply, State}.
Таким образом, вы можете использовать этот механизм и обрабатывать ошибки тайм-аута. Но реальный вопрос здесь такой: ожидаете ли вы ошибок тайм-аута вообще?
Что касается таймера: да, у таймера есть некоторые накладные расходы в случае, если вы планируете делать DDOS-атаки или что-то в этом роде :-D Если вы не планируете создавать и отменять таймеры, такие как сумасшедшие, гораздо более элегантно использовать модуль таймера , Это выбор дизайна, который вы должны сделать: хотите ли вы чистый и элегантный код или код, который может стоять, когда все остальное ломается. Я сомневаюсь, что вам нужно последнее. Но вы знаете лучше.