Какие типы могут быть отправлены в сообщении Erlang?

#erlang #erlang-otp #gen-server

#erlang #erlang-otp #gen-server

Вопрос:

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

На компьютере 1:

 F1 = Fun()-> hey end,

gen_server:call(on_other_machine,F1)
  

На компьютере 2:

 handler_call(Function,From,State) ->
{reply,Function(),State)
  

Имеет ли это смысл?

Ответ №1:

Вот интересная статья о «передаче функций другим узлам Erlang». Чтобы кратко продолжить:

[…] Как вы, возможно, знаете, дистрибутив Erlang работает путем отправки двоичной кодировки терминов; и поэтому отправка fun также по существу выполняется путем кодирования его с помощью erlang:term_to_binary /1; передачи результирующего двоичного файла другому узлу, а затем его повторного декодирования с помощью erlang:binary_to_term /1.[…] Это довольно очевидно для большинства типов данных; но как это работает для функциональных объектов?

Когда вы кодируете fun, то, что кодируется, является просто ссылкой на функцию, а не на реализацию функции. […]

[…] определение функции не передается вместе; информации ровно столько, чтобы воссоздать процесс на другом узле, если модуль там есть.

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

[…] Если вы никогда не пытаетесь применить функцию, то ничего плохого не произойдет. Забава может быть передана другому узлу (на котором находится рассматриваемый модуль / забава), и тогда все довольны. Возможно, на целевом узле загружен модуль с указанным именем, но, возможно, в другой версии; который тогда, с большой вероятностью, будет иметь другую контрольную сумму MD5, тогда вы получите ошибку badfun, если попытаетесь ее применить.

Я бы посоветовал вам прочитать статью целиком, потому что она чрезвычайно интересна.

Ответ №2:

Вы можете отправить любой допустимый термин Erlang. Хотя вы должны быть осторожны при отправке funs. Для любого развлечения, ссылающегося на функцию внутри модуля, этот модуль должен существовать на целевом узле для работы:

 (first@host)9> rpc:call(second@host, erlang, apply,
                        [fun io:format/1, ["Hey!~n"]]).
Hey!
ok
(first@host)10> mymodule:func("Hey!~n").
5
(first@host)11> rpc:call(second@host, erlang, apply,
                         [fun mymodule:func/1, ["Hey!~n"]]).
{badrpc,{'EXIT',{undef,[{mymodule,func,["Hey!~n"]},
                        {rpc,'-handle_call_call/6-fun-0-',5}]}}}
  

В этом примере io существует на обоих узлах и работает для отправки функции из io в качестве развлечения. Однако, mymodule существует только на первом узле, и fun генерирует undef исключение при вызове на другом узле.

Комментарии:

1. Как насчет анонимных функций?

2. Если под этим вы подразумеваете анонимные забавы, то у него та же проблема. Т.е. модуль, в котором он определен, должен существовать на удаленном узле.

Ответ №3:

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

t1@localhost:

 (t1@localhost)7> register(shell, self()).
true
(t1@localhost)10> A = me, receive Fun when is_function(Fun) -> Fun(A) end.
hello me you
ok
  

t2@localhost:

 (t2@localhost)11> B = you.
you
(t2@localhost)12> Fn2 = fun (A) -> io:format("hello ~p ~p~n", [A, B]) end.
#Fun<erl_eval.6.54118792>
(t2@localhost)13> {shell, 't1@localhost'} ! Fn2.
  

Я добавляю логику покрытия в приложение, построенное на riak-core, и объединение собранных результатов может быть сложным, если анонимные функции не могут быть использованы в сообщениях.

Также проверьте riak_kv/src/riak_kv_coverage_filter.erl

я полагаю, riak_kv может использовать это для filter получения результата.