Может ли кто-нибудь объяснить структуру Pid в Erlang?
Вопрос
Может ли кто-нибудь объяснить структуру Pid в Erlang?
Пиды выглядят так: <A.B.C>
, например<0.30.0>, но мне хотелось бы знать, что означают эти три «бита»:А, Б и С.
Кажется, что «A» всегда равно 0 на локальном узле, но это значение меняется, когда владелец Pid находится на другом узле.
Можно ли напрямую отправить сообщение на удаленный узел, используя только Pid?Что-то вроде того :<4568.30.0> !Сообщение, без необходимости явного указания имени зарегистрированного процесса и имени узла ({proc_name, Node}!Сообщение ) ?
Решение
Напечатанные идентификаторы процессов <A.B.C> состоят из 6:
- A, номер узла (0 — локальный node, произвольное число для удаленного узла)
- B, первые 15 бит номера процесса (индекс в таблице процессов) 7
- C, биты 16-18 номера процесса (тот же номер процесса, что и B) 7
Внутренняя ширина номера процесса в 32-битном эмуляторе составляет 28 бит.Странное определение B и C взято из R9B и более ранних версий Erlang, в которых B представлял собой 15-битный идентификатор процесса, а C — счетчик переноса, увеличивающийся при достижении максимального идентификатора процесса и повторно использовались более низкие идентификаторы.
В распределении Эрланга PID немного больше, поскольку они включают в себя атом узла, а также другую информацию.(Распределенный формат PID)
Когда внутренний PID отправляется с одного узла на другой, он автоматически преобразуется во внешнюю/распределенную форму PID. <0.10.0>
(inet_db
) на одном узле может закончиться как <2265.10.0>
при отправке на другой узел.Вы можете просто отправить эти PID как обычно.
% get the PID of the user server on OtherNode
RemoteUser = rpc:call(OtherNode, erlang,whereis,[user]),
true = is_pid(RemoteUser),
% send message to remote PID
RemoteUser ! ignore_this,
% print "Hello from <nodename>\n" on the remote node's console.
io:format(RemoteUser, "Hello from ~p~n", [node()]).
Для получения дополнительной информации см.: Внутренняя структура ПИД-регулятора, Информация о создании узла, Взаимодействие счетчика создания узла с EPMD
Другие советы
Если я правильно помню это, то формат <nodeid,serial,creation>
.
0 является текущим узлом, так же как компьютер всегда имеет имя хоста & Quot; localhost & Quot; ссылаться на себя. Это старая память, поэтому она не может быть на 100% правильной.
Но да. Например, вы можете создать pid с помощью list_to_pid/1
.
PidString = "<0.39.0>",
list_to_pid(PidString) ! message.
Конечно. Вы просто используете любой метод, который вам нужен для создания вашей PidString. Вероятно, напишите функцию, которая ее генерирует, и используйте ее вместо PidString, например:
list_to_pid( make_pid_from_term({proc_name, Node}) ) ! message
Идентификатор процесса <A.B.C> состоит из:
- A, идентификатор узла, который не является произвольным, а является внутренним индексом этого узла в dist_entry.(На самом деле это целое число слота атома для имени узла.)
- B, индекс процесса, который относится к внутреннему индексу в proctab (0 -> MAXPROCS).
- C, серийный номер, который увеличивается каждый раз, когда достигается MAXPROCS.
Двухбитовый тег создания не отображается в pid, но используется внутри и увеличивается при каждом перезапуске узла.
PID относится к процессу и таблице узлов. Таким образом, вы можете отправить сообщение непосредственно в PID, только если оно известно на узле, с которого вы выполняете вызов.
Возможно, это сработает, если узел, с которого вы выполняете вызов, уже знает о узле, на котором запущен процесс. Р>
Помимо того, что сказали другие, вам может пригодиться этот простой эксперимент, чтобы понять, что происходит внутри:
1> node().
nonode@nohost
2> term_to_binary(node()).
<<131,100,0,13,110,111,110,111,100,101,64,110,111,104,111,
115,116>>
3> self().
<0.32.0>
4> term_to_binary(self()).
<<131,103,100,0,13,110,111,110,111,100,101,64,110,111,104,
111,115,116,0,0,0,32,0,0,0,0,0>>
Итак, вы можете убедиться, что имя узла хранится внутри pid. Дополнительную информацию можно найти в этом разделе раздела "Изучите вас на некоторых языках Erlang".