Какой смысл Spawn(Node, Fun) на erlang, если Node должен иметь тот же модуль, который загружается как клиентский узел?

Зачем создавать иллюзию, что вы отправляете Fun на удаленный узел для выполнения в новом процессе? Если клиентский узел должен иметь такой же загружаемый модуль с Fun, определенным как узел сервера в любом случае. Почему бы не только порождать (Node, M, F, A), что дает понять, что вы отправляете определение вызова функции, а не саму Fun.

2 ответа

Давайте рассмотрим два возможных случая

Функции, относящиеся к функциям модуля

Fun = fun file:getcwd/0,
erlang:spawn(Node, Fun). 

В этом случае Fun действительно должен быть загружаемым на удаленной стороне.

Анонимные функции

Fun = fun() -> io:format("My node is ~p~n", [node()]) end,
erlang:spawn(Node, Fun). 

Они также могут быть вызваны.

подведение

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

Также

Некоторые заблуждения могут пойти из этой статьи

На самом деле, если вы запускаете erlang:fun_info для анонимной функции вы увидите, что она обеспечивает реализацию в форме AST

(b@lol4t0-home)21> rp(erlang:fun_info(fun() -> io:format("My node is ~p~n", [node()]) end)). 
[{pid,<0.96.0>},
 {module,erl_eval},
 {new_index,20},
 {new_uniq,<<99,62,121,82,122,95,246,237,63,72,118,40,4,
             25,16,50>>},
 {index,20},
 {uniq,52032458},
 {name,'-expr/5-fun-3-'},
 {arity,0},
 {env,[{[],
        {eval,#Fun<shell.21.31625193>},
        {value,#Fun<shell.5.31625193>},
        [{clause,1,[],[],
                 [{call,1,
                        {remote,1,{atom,1,io},{atom,1,format}},
                        [{string,1,"My node is ~p~n"},
                         {cons,1,{call,1,{atom,1,node},[]},{nil,1}}]}]}]}]},
 {type,local}]

Пример ниже показывает, что удаленный узел может выполнить код, который никогда не был загружен на него, даже вызов анонимной функции, которая была определена на узле вызывающего:

на узле Тити

Erlang/OTP 19 [erts-8.0] [64-bit] [smp:4:4] [async-threads:10]

Eshell V8.0  (abort with ^G)
(titi@XXXXXXXX)1> net_adm:ping(toto@XXXXXXXX).
pong
(titi@XXXXXXXX)2> F = fun F(X) -> receive {plus,N} -> F(X+N); get -> io:format("state is ~p~n",[X]), F(X); stop -> bye end end. 
#Fun<erl_eval.30.52032458>
(titi@XXXXXXXX)3> G = fun() -> register(server,self()), F(0) end.
#Fun<erl_eval.20.52032458>
(titi@XXXXXXXX)4> spawn(toto@XXXXXXXX,G).
<7039.67.0>
state is 0           
state is 5           
state is 10          
(titi@XXXXXXXX)5> 

на узле тото

Erlang/OTP 19 [erts-8.0] [64-bit] [smp:4:4] [async-threads:10]

Eshell V8.0  (abort with ^G)
(toto@XXXXXXXX)1> server ! get. % will print state is 0
get
(toto@XXXXXXXX)2> server ! {plus,5}. % new state = 5
{plus,5}
(toto@XXXXXXXX)3> server ! get. % will print state is 5    
get
(toto@XXXXXXXX)4> server ! {plus,5}. % new state = 10
{plus,5}
(toto@XXXXXXXX)5> server ! get. % will print state is 10     
get
(toto@XXXXXXXX)6> server ! stop. % ends the server process    
stop
(toto@XXXXXXXX)7> server ! get. % message will fail
** exception error: bad argument
     in operator  !/2
        called as server ! get
(toto@XXXXXXXX)8> 

Я также проверил, что если вы замените код {plus,N} -> F(X+N); от {plus,N} -> F(maps:put(X,X+N,maps:new())); который вызывает модуль, не загруженный оболочкой при запуске, он также работает нормально.

редактировать

Прочитайте комментарии, кажется, что делать тест в оболочке не правильно, 2 вывода, хотя:

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