8

主要是我想知道我是否可以在分布式 Erlang 设置中的消息中发送函数。

在机器 1 上:

F1 = Fun()-> hey end,

gen_server:call(on_other_machine,F1)

在机器 2 上:

handler_call(Function,From,State) ->
{reply,Function(),State)

是否有意义?

4

3 回答 3

8

是一篇关于“将乐趣传递给其他 Erlang 节点”的有趣文章。简单地恢复它:

[...] 如您所知,Erlang 分发通过发送术语的二进制编码来工作;因此发送乐趣本质上也是通过使用 erlang:term_to_binary/1; 对其进行编码来完成的。将生成的二进制文件传递给另一个节点,然后使用 erlang:binary_to_term/1 再次对其进行解码。[...] 这对于大多数数据类型来说是非常明显的;但它对函数对象是如何工作的?

当你对一个 fun 进行编码时,编码的只是对函数的引用,而不是函数实现。[...]

[...]函数的定义没有传递;如果模块在那里,正好有足够的信息在另一个节点上重新创造乐趣。

[...] 如果包含 fun 的模块尚未加载,并且目标节点正在交互模式下运行;然后尝试使用常规模块加载机制(包含在模块 error_handler 中)加载模块;然后它会尝试查看具有给定 id 的乐趣是否在所述模块中可用。但是,这只会在您尝试应用该功能时懒惰地发生。

[...] 如果您从不尝试应用该功能,那么就不会发生任何不好的事情。乐趣可以传递到另一个节点(有问题的模块/乐趣),然后每个人都很开心。也许目标节点有一个加载了该名称的模块,但可能是不同的版本;然后很可能有不同的 MD5 校验和,如果您尝试应用它,则会收到错误 badfun。

我建议你阅读整篇文章,因为它非常有趣。

于 2011-05-24T14:21:00.013 回答
6

您可以发送任何有效的 Erlang 术语。尽管发送乐趣时必须小心。任何在模块内引用函数的乐趣都需要该模块存在于目标节点上才能工作:

(first@host)9> rpc:call(second@host, erlang, apply,
                        [fun io:format/1, ["Hey!~n"]]).
Hey!
ok
(first@host)10> mymodule:func("Hey!~n").
5
(first@host)11> rpc:call(second@host, erlang, apply,
                         [fun mymodule:func/1, ["Hey!~n"]]).
{badrpc,{'EXIT',{undef,[{mymodule,func,["Hey!~n"]},
                        {rpc,'-handle_call_call/6-fun-0-',5}]}}}

在这个例子中,io两个节点上都存在,它可以发送一个函数io作为一种乐趣。但是,mymodule仅存在于第一个节点上,并且 funundef在另一个节点上调用时会生成异常。

于 2011-05-24T13:52:28.967 回答
4

至于匿名函数,它们似乎可以按预期发送和工作。

t1@localhost:

(t1@localhost)7> register(shell, self()).
true
(t1@localhost)10> A = me, receive Fun when is_function(Fun) -> Fun(A) end.
hello me you
ok

t2@localhost:

(t2@localhost)11> B = you.
you
(t2@localhost)12> Fn2 = fun (A) -> io:format("hello ~p ~p~n", [A, B]) end.
#Fun<erl_eval.6.54118792>
(t2@localhost)13> {shell, 't1@localhost'} ! Fn2.

我正在向基于 riak-core 构建的应用程序添加覆盖逻辑,如果无法在消息中使用匿名函数,则收集的结果的合并可能会很棘手。

另请查看riak_kv/src/riak_kv_coverage_filter.erl

我猜riak_kv 可能正在使用它来filter产生结果。

于 2016-04-01T10:30:23.957 回答