erlang:未能生成(节点,乐趣):badfun错误

erlang:未能生成(节点,乐趣):badfun错误,erlang,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@lo

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

我从本地节点进行测试:

$ 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
$erl-名称foobar
Erlang/OTP 17[erts-6.2][source][64位][smp:2:2][async threads:10][kernel poll:false]
Eshell V6.2(使用^G中止)
(foobar@debian.localdomain)1> 阿里云aliyun@localhost2.localdomain'.
'aliyun@localhost2.localdomain'
(foobar@debian.localdomain)2> 繁殖(Aliyun,fun()->io:format(“hello~n”)结束)。
(foobar@debian.localdomain)3> 
=错误报告===2015年7月4日::21:03:27===
节点“”上的进程出错aliyun@localhost2.localdomain'的退出值:{{badfun,#Fun},[{erlang,apply,2,[]}
(foobar@debian.localdomain)3> 生成(Aliyun,io,format,[“hello~n”])。
你好
(foobar@debian.localdomain)4> 净行政:平(阿里云)。
庞
您可以看到
spawn(节点、模块、函数、参数)
可以工作,但是
spawn(节点、乐趣)
不能

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


救命啊

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

一个有趣的尝试是在R15节点上定义匿名函数,通过
term\u to\u binary/1
将其转换为二进制,将生成的二进制发送或复制到17.x节点,通过
binary\u to\u term/1
将其转换回一个term,然后将结果项作为匿名函数传递给
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
(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节点只是通过它。

为什么它被限制为同一版本的erl_eval?只要fun与目标版本兼容,即引用的函数和语义兼容,那么它就应该在目标Erlang上运行,这更灵活,因为您可以在节点之间交换任意兼容的代码,除了准备好的模块之外,您建议如何验证模块功能和语义的兼容性,以便与该模块关联的任意匿名FUN可以在不同节点上正确执行?解决那个问题通常是不切实际的。因此,Erlang运行时检查模块的MD5校验和以验证兼容性。