What is the point of Spawn(Node, Fun) on erlang, if Node has to have the same module loadable as a client node?

帅比萌擦擦* 提交于 2019-12-01 19:59:59

问题


Why create illusion that you are sending a Fun to remote node to execute in a new process? If client node has to have same module loadable with the Fun defined as a server node anyway. Why not only spawn(Node, M, F, A) then, which makes it clear that you are sending a definition of a function call, not Fun itself.


回答1:


Let's consider two possible cases

Functions referring to module functions

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

In this case Fun indeed should be loadable at the remote side.

Anonymous functions

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

They are callable also.

Summarizing

While there some limitations implied to a function, that can be spwaned remotely, this form is still suitable and can be dropped, because then second case would become impossible

Also

Some misconceptions might go from this article

Actually, if you run erlang:fun_info for anonymous function, you'll see, that it provides implementation in a form of 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}]



回答2:


The example below shows that the remote node can execute a code that was never loaded on it, even a call to an anonymous function that was defined on the caller node:

on node titi

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> 

on node toto

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> 

I also checked that if you replace the code {plus,N} -> F(X+N); by {plus,N} -> F(maps:put(X,X+N,maps:new())); which is calling a module not loaded by the shell at start, it works fine as well.

Edit

Read the comments, it seems that doing the test in the shell is not the right way, 2 conclusions though:

  • do not rely on the shell only to make verifications,
  • there should be a way to execute on the remote node a code that was only known on the caller node since the shell can do it...


来源:https://stackoverflow.com/questions/39255471/what-is-the-point-of-spawnnode-fun-on-erlang-if-node-has-to-have-the-same-mo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!