Как визуально описать gen_server?

Заявление об ограничении ответственности: автор - новичок в OTP, обладающий некоторыми базовыми знаниями синтаксиса, процессов и сообщений Erlang.

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

Хорошо, официальная документация для gen_server показывает красивую диаграмму сервера и трех клиентов, связанных стрелками запроса и ответа: http://www.erlang.org/doc/design_principles/gen_server_concepts.html

Но каждый раз, когда я пытаюсь понять эту концепцию дальше, я застреваю.

Есть много концепций, которые я не могу объединить в одну большую концепцию в своей голове:

  • реализация поведения;
  • контейнер поведения;
  • интерфейс поведения;
  • модуль обратного вызова;
  • функции обратного вызова;
  • Функции API.

Я использую следующие ресурсы:

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

Есть ли способ описать понятие gen_server на диаграмме? Как можно визуально показать поток взаимодействия между клиентами и сервером? (чтобы помочь не очень умному новичку понять концепцию визуально)

Например, как здесь: http://support.novell.com/techcenter/articles/img/dnd2003080506.gif

UPD: Я попытался нарисовать свою схему, но до сих пор не понимаю назначение какого-либо соединителя на схеме: http://postimage.org/image/qe215ric/full/

UPD2: Это похоже на то, что я хотел бы видеть: http://cryptoanarchy.org/wiki/Worker_patterns (Модель). Однако он не показывает взаимодействие между модулями, функциями и процессами.


person skanatek    schedule 11.08.2011    source источник
comment
Мартин, одна из вещей, которые могут сбить с толку, это регистрация singleton gen_server. В большинстве руководств я рассматриваю это как первое введение в gen_server, и это сбивает с толку, если вы пытаетесь понять gen_server. Итак, {local, CH3} в start_link делает его одиночным - ›будет только один процесс модуля gen_server, на который вы смотрите.   -  person Ward Bekker    schedule 11.08.2011
comment
@WardB Спасибо, я учту это.   -  person skanatek    schedule 11.08.2011
comment
воах !!! Вы вообще не упомянули книгу Армстронга ... прагматичное программирование !!! Вы ДОЛЖНЫ пройти через это. У него очень простое и пошаговое руководство по OTP.   -  person Arunmu    schedule 11.08.2011
comment
@AruMu Как я писал автору LYSE, ваш совет был действительно полезен, спасибо!   -  person skanatek    schedule 16.08.2011


Ответы (1)


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

Чтобы помочь с отдельными компонентами:

реализация поведения

Само поведение немного похоже на то, что показано в главе, на которую я ссылался ранее. Это модуль с множеством функций, выполняющих все стандартные функции за вас: получение сообщений, определение функций и скрытых протоколов для связи и т. Д. Расширенный материал OTP содержит особые виды сообщений, используемых для обновления программного обеспечения, а также специальный код для параметров отслеживания.

контейнер поведения

Я не уверен, что это должно быть. Может просто модуль с названием поведения?

интерфейс поведения

В том же модуле, в котором реализована ваша реализация поведения, вы должны определить функцию behaviour_info/1. Эта функция сообщит компилятору Erlang, что некоторые обратные вызовы ожидаются от любого модуля, в котором есть -behaviour(SomeModuleName). SomeModuleName эквивалентен файлу SomeModuleName.erl.beam), который содержит реализацию и функцию behavior_info.

модуль обратного вызова

Модуль, который будет содержать весь конкретный код, обрабатывающий все настраиваемые вещи.

функции обратного вызова

Все, что не является универсальным, делегируется модулю обратного вызова в форме YourModule:SomeCall(Args). Они предоставляются вашим модулем, в котором есть строка -behaviour(gen_server)..

Функции API

Модуль обратного вызова имеет два интерфейса, если хотите: один для поведения gen_server (init / 0, handle_call / 3, handle_info / 2, handle_cast / 2, terminate / 2, code_change / 3) и один для пользователя ( запускаем сервер, отправляем некоторую информацию, запрашиваем информацию обратно).

Я мог бы попытаться описать это так

---------------------------------------------------------------------
| some process          |                server process             |
------------------------+--------------------------------------------
   [client]             |      [callback]     :        [behaviour]
                        |                     :
 callback:start >-------|---------------------:--> starting the process
                        |                     :           V
                        |                     :           |
                        |       init()  <-----:-----------`
                        |         |           :
                        |         `-----------:------> initial state
  {ok, Pid}  <----------|---------------------:----------,/
                        |                     :
 callback:store  >------|---------------------:--> handles message
 (calls the process)    |    (formats msg)    :           V
                        |                     :           |
                        |    handle_call() <--:-----------` 
                        |         |           :
                        |          `----------:--> updates state, sends reply
                        |                     :        V
                        |                     :        |
   gets result <--------|---------------------:--------`
                        |                     :       

Все общие части находятся справа от серверного процесса внутри поведения, а все конкретные части находятся слева (обратный вызов). Клиент использует API / интерфейс модуля обратного вызова, чтобы связаться с серверным процессом и оказать на него влияние.

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

Надеюсь, это поможет.

person I GIVE TERRIBLE ADVICE    schedule 11.08.2011
comment
Хороший ответ, спасибо! Сочетание вашего рисунка и совета прочитать книгу Армстронга помогло мне понять эту концепцию. Между прочим, как вы думаете, лучше ли изучать OTP с очень базовыми знаниями самого Erlang, как предлагает «Erlang / OTP in Action»? (стр. 92: Вам не нужны какие-либо предварительные знания о модулях, процессах, функциях или сообщениях, чтобы понять ... - person skanatek; 16.08.2011
comment
Я не согласен с этим, нет. Однако это может зависеть от того, как я учусь по сравнению с некоторыми другими людьми. Мне нравятся фреймворки, когда я могу понять, почему они такие, какие они есть, и какие проблемы они решают, кроме «упрощения работы». Мне нравится знать, что OTP делает для меня и на каких принципах он был построен. Я считаю, что это помогает мне уважать исходную идею и облегчает ее развитие. Вы увидите, как я показываю вещи в LYSE: покажите, зачем нам нужны абстракции, затем покажите, как грубо построить абстракцию, затем покажите структуру. - person I GIVE TERRIBLE ADVICE; 16.08.2011
comment
Для меня совершенно очевидно, что у некоторых других людей есть другие способы обучения, которые более естественны для них. - person I GIVE TERRIBLE ADVICE; 16.08.2011