erlang:生成失败(节点,乐趣):badfun 错误

erlang: failed to spawn(node, fun): badfun error

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

我从本地节点测试:

$ 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 在将 fun 类型传递给远程节点时是如何编组的。在字节码中?

请帮忙!

如您收到的错误消息所示,在此上下文中,匿名函数基本上被视为在 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 节点只是通过它。