Подходит ли словарь процессов в этом случае? - PullRequest
7 голосов
/ 02 ноября 2010

Я прочитал несколько комментариев здесь и в других местах, предполагая, что словарь процессов Эрланга был плохой идеей и должен умереть. Обычно, как новичок в Erlang, я бы просто избегал этого. Однако в этой ситуации другие мои варианты не очень хороши.

У меня есть главная диспетчерская функция, которая выглядит примерно так:

dispatch(State) ->
    receive
        {cmd1, Params} ->
            NewState = do_cmd1_stuff(Params, State),
            dispatch(NewState);
        {cmd2, Params} ->
            NewState = do_cmd2_stuff(Params, State),
            dispatch(NewState);
        BadMsg ->
            log_error(BadMsg),
            dispatch(State)
    end.

Очевидно, мои имена более значимы для меня, но в этом суть. В глубине функции, вызываемой функцией, вызываемой функцией do_cmd2_stuff (), я хочу отправлять сообщения всем своим пользователям, рассказывая им о том, что я сделал. Для этого мне нужно получить список пользователей с того места, куда я отправляю сообщения. Список пользователей нелегко придерживаться глобального состояния, поскольку это всего лишь одна структура данных, представляющая единственный блок данных, над которым я работаю.

На мой взгляд, у меня есть пара неприятных вариантов, кроме использования словаря процессов. Я могу отправить список пользователей через все различные уровни функций до самого нижнего уровня, который выполняет вещание. Это неприятно, потому что все мои функции получают параметр, независимо от того, заботятся ли они об этом или нет.

В качестве альтернативы, я мог бы заставить все функции do_cmdN_stuff() вернуть сообщение для отправки. Это тоже не очень хорошо, так как отправка сообщения может быть не последней вещью, которую я хочу сделать, и она загромождает моего диспетчера кучей {Msg, NewState} кортежей. Кроме того, некоторые функции могут не иметь сообщений для отправки.

Как я уже говорил ранее, я очень плохо знаком с Эрлангом. Может быть, кто-то с большим опытом может указать мне на лучший путь. Есть один? Подходит ли словарь процессов в этом случае?

Ответы [ 6 ]

4 голосов
/ 02 ноября 2010

Простым ответом будет размещение вашего глобального объекта в записи состояния, которая затем проходит через систему, по крайней мере, на уровне остановки. Это упрощает добавление новых полей в состояние в будущем, что не является необычным явлением, и позволяет сохранить структуру данных глобального состояния без изменений. Итак, изначально

-record(state, {users=[],state_data}).

Определение его как записи облегчает доступ и расширение при необходимости.

3 голосов
/ 02 ноября 2010

Общее правило: если у вас есть сомнения, вам не следует использовать словарь процессов.

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

Pid ! {forward, Msg}

, где Pid позаботится об отправке всего в кучу других процессов. Теперь вам все равно нужно будет передать Pid, ​​если вы не дадите ему имя в каком-либо реестре, чтобы найти его. Либо с register/2, global или gproc.

1 голос
/ 04 ноября 2010

Это интересный вопрос, потому что он затрагивает основы функционального дизайна.

Мое мнение: Постарайтесь сделать так, чтобы функция возвращала сообщения, а затем отправляла их.Это прекрасно разделяет две разные задачи и отделяет чисто функциональную задачу от задачи, вызывающей побочные эффекты.

Если это невозможно, передайте получатели в качестве аргумента, даже если они немного грязные.Если широковещательная функция использует эти данные, она должна быть передана ей явно для ясности и предсказуемости.

Использование ETS, как полагает Пир Стрицингер, на самом деле не лучше, чем PD, оба скрывают тот факт, что функция широковещанияиспользует список получателей и делает его зависимым от глобальных данных.

Я не уверен, каким образом Эрланг инкапсулирует какое-либо состояние в процессе, как я предлагаю, ДАЯ УЖАСНЫЙ СОВЕТ.Действительно ли лучше, чем ETS или PD?

загромождает моего диспетчера кучей {Msg, NewState}

Это также мой опыт, что вы частов конечном итоге, как это.Это не особенно красиво, но функциональный дизайн, кажется, поощряет это.Могут ли быть введены некоторые языковые функции, чтобы сделать их более красивыми и естественными?

РЕДАКТИРОВАТЬ:

6 лет назад я писал:

Могут ли некоторые языковые функции быть введены всделать его более красивым и естественным?

Узнав намного больше о функциональном программировании, я понял, что примерами этого являются монады и do-notation , которые можно найти в Haskell.

1 голос
/ 02 ноября 2010

Вы действительно не должны использовать словарь процесса. Я принимаю использование словаря, только если

  1. Это короткий жизненный процесс.
  2. У меня есть полный контроль над процессом от порождения до завершения, т.е. я использую минимальный и хорошо известный набор внешних модулей.
  3. Мне нужен прирост производительности. Это означает, что следует избегать копирования данных при использовании ets, а dict / gb_tree слишком медленный (по причине GC).

ad 1. это не ваш случай, вы используете на сервере. объявление 2. Я не знаю, если это ваш случай. Объявление 3. не ваше дело, потому что вам нужен список получателей, чтобы вы ничего не получили от этого словаря процессов, это очень быстрое хранилище ключей / значений. В вашем случае я не вижу причин, по которым вы не должны включать то, что вам нужно, в свой State. ИМХО State это именно то, что нужно для него.

1 голос
/ 02 ноября 2010

Как вы упомянули, вы всегда можете передать список пользователей как дополнительный параметр, это не так уж и плохо.

Если вы не хотите этого делать, просто поместите его в State.Вы можете иметь специальное состояние только для этой части расчета, которая также содержит список пользователей.

Тогда всегда есть возможность поместить его в ETS или в другой серверный процесс.

Что конкретно делать, рекомендовать сложно, так как это во многом зависит от вашего конкретного приложения и предпочтений.

Просто выберите из упомянутых возможностей, как будто словарь процессов не существует.Может быть, ваш код нуждается в реструктуризации, если ни один из вариантов не выглядит элегантно, всегда есть лучший способ без словаря процессов.

Это действительно плохо, он все еще там, потому что он привлекает многих начинающих пользователей Erlang.

0 голосов
/ 16 декабря 2016

Я бы посоветовал отправить специальное сообщение на self() из глубины стека вызовов и обработать его на верхнем уровне dispatch метода, который вы набросали, где доступен список пользователей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...