erlang:无法生成(节点,有趣):badfun错误

时间:2015-07-04 13:15:53

标签: erlang

远程节点位于不同的计算机上。

我从本地节点测试:

$ erl -name foobar
Erlang/OTP 17 [erts-6.2] [source] [64-bit] [smp:2:2] [async-threads:10] [kernel-poll:false]

Eshell V6.2  (abort with ^G)
(foobar@debian.localdomain)1> Aliyun='aliyun@localhost2.localdomain'.
'aliyun@localhost2.localdomain'
(foobar@debian.localdomain)2> spawn(Aliyun, fun() -> io:format("hello~n") end).
<6108.86.0>
(foobar@debian.localdomain)3> 
=ERROR REPORT==== 4-Jul-2015::21:03:27 ===
Error in process <0.86.0> on node 'aliyun@localhost2.localdomain' with exit value: {{badfun,#Fun<erl_eval.20.90072148>},[{erlang,apply,2,[]}]}


(foobar@debian.localdomain)3> spawn(Aliyun, io, format, ["hello~n"]).          
hello
<6108.87.0>
(foobar@debian.localdomain)4> net_adm:ping(Aliyun).
pong

您可以看到spawn(node,module,function,args)有效,但spawn(node,fun)没有。

远程节点上的Erlang版本是R15,而本地节点上的版本是R17。是原因吗?因为代码格式不同?我不清楚Erlang如何在将它传递给远程节点时编组有趣的类型。在字节码?

请帮忙!

1 个答案:

答案 0 :(得分:9)

正如您收到的错误消息所示,匿名函数在此上下文中基本上被视为在erl_eval模块中定义。如果在发送节点和接收节点上都有相同版本的erl_eval,那么一切正常,因为在这种情况下,erl_eval的两个副本都具有相同的版本和校验和,因此接收节点是正确的能够评估从发送节点传递的匿名函数。但是如果两个节点具有不同的erl_eval模块,则评估匿名函数将失败。

尝试一个有趣的事情是在R15节点上定义匿名函数,通过term_to_binary/1将其转换为二进制,将生成的二进制文件发送或复制到17.x节点,将其转换回术语来自binary_to_term/1,然后将生成的术语作为匿名函数传递给spawn来电。首先,在R15节点上:

(r15@myhost)1> F = fun() -> io:format("hello~n") end.
(r15@myhost)2> Bin = term_to_binary(F).
<<131,112,0,0,2,179,0,158,45,156,12,16,101,74,154,214,21,
  222,196,219,108,205,131,0,0,0,20,0,0,...>>
(r15@myhost)3> file:write_file("/tmp/fun", Bin).
ok

现在将二进制文件读入17.x节点,然后用spawn调用它回到R15节点:

(r17@myhost)1> {ok, Bin} = file:read_file("/tmp/fun").
{ok,<<131,112,0,0,2,179,0,158,45,156,12,16,101,74,154,
      214,21,222,196,219,108,205,131,0,0,0,20,...>>}
(r17@myhost)2> F = binary_to_term(Bin).
#Fun<erl_eval.20.82930912>
(r17@myhost)3> spawn(r15@myhost, F).
hello
<7101.90.0>

正如您所看到的 - 您也应该亲自尝试 - spawn调用按预期工作,因为匿名函数是在R15节点上创建的,并且它也在那里进行评估。 17.x节点只传递它。