Как описать gen_server визуально? - PullRequest
7 голосов
/ 11 августа 2011

Отказ от ответственности: автор является новичком в OTP, обладающим некоторыми базовыми знаниями о синтаксисе, процессах и сообщениях Эрланга.

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

Хорошо, официальная документация для gen_server показывает симпатичную схему сервера и трех клиентов, связанных стрелками Query и Reply: 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 (Модель).Тем не менее, он не показывает взаимодействие между модулями, функциями и процессами.

1 Ответ

12 голосов
/ 11 августа 2011

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

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

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

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

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

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

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

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

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

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

...