Erlang:将客户端进程/功能卸载到服务器吗?

Eit*_*tan 5 erlang distributed-computing hotswap

我的情况如下-我有一个带有函数foo()的客户端C,它执行一些计算。

我希望不知道foo()的服务器S执行此功能,然后将结果发送回客户端。

我正在尝试确定在Erlang中执行此操作的最佳方法。我正在考虑:

  • 热代码交换-即S中的“升级”代码,使其具有功能foo()。执行并发送回客户端。
  • 在所有节点都被适当注册的分布式方式中,沿着S的方向做点事情C:foo() -为了“发送”功能到进程/节点S

我还没有想到其他方法(或语言的功能)吗?

谢谢您的帮助!

Muz*_*hua 3

如果计算功能是自包含的,即不依赖于客户端C上的任何其他模块或功能,那么您需要做的是fun(功能对象)。Afun可以通过网络发送并由远程计算机应用,并且在 中fun,发送者嵌入了他们的地址和获取答案的方法。因此,执行者可能只会看到fun他们可能会或可能不会给出参数的一个,但在乐趣中,发送者强制采用了一种方法,其中答案将自动发回。它fun是一个事物中许多任务的抽象,它可以作为参数移动。
在客户端,您可以使用如下代码:

%% 客户端中的某处
%% 客户端在 node() == 'client@domain.com' 上运行

-模块(客户端)。
-编译(导出全部)。
-define(SERVER,{server,'server@domain.com'})。

Give_a_server_a_job(Number)-> ?服务器!{build_fun(),数字}。

build_fun()->
    FunObject = fun(参数)->
                    答案 = Param * 20/1000, %% 计算在这里
                    rpc:call('client@domain.com',client,answer_ready,[答案])
                结尾,
    有趣的对象。

answer_ready(答案)->
    %%% 使用 Answer 来处理各种有趣的事情......
    io:format("\n\t答案在这里:~p~n",[答案])。

然后服务器有这样的代码:

%%% 服务器上的某处
%%% 服务器在 node() == 'server@domain.com' 上运行

-模块(服务器)。
-编译(导出全部)。

开始()->注册(服务器,生成(?模块,循环,[]))。

循环()->
    收到
        {有趣,Arg} ->
            Fun(Arg), %% 服务器执行作业
                        %% 作业自动发回应答
                        %% 给客户
            环形();
        停止->退出(正常);
        _ -> 循环()
    结尾。

这样,作业执行者不需要知道如何发回回复,作业本身就知道它将如何发回答案给发送的作业!。我在几个项目中使用过这种通过网络发送功能对象的方法,它太酷了!

#### 编辑######

如果您有递归问题,您可以使用funs. 但是,您在客户端和/或服务器上至少需要一个库函数来协助递归操作。创建一个函数,该函数应位于客户端和服务器的代码路径中。

另一种选择是动态地将代码从服务器发送到客户端,然后使用该库:Dynamic Compile erlang从客户端在服务器上加载并执行 erlang 代码。使用动态编译,下面是一个例子:

1> String = "-module(add).\n -export([add/2]).\n add(A,B) -> A + B.\n"。
"-module(add).\n -export([add/2]).\n add(A,B) -> A + B。\n"
2> 动态编译:从字符串加载(字符串)。
{模块,添加}
3> 添加:添加(2,5)。
7
4>

我们上面看到的是一段从字符串动态编译和加载的模块代码。如果启用此功能的库在服务器和客户端上可用,则每个实体都可以将代码作为字符串发送,并在另一个实体上动态加载和执行。此代码使用后可以卸载。让我们看看斐波那契函数以及如何在服务器上发送和执行它:

%% 这是我们要转换为字符串的普通斐波那契代码:

-模块(fib)。
-导出([fib/1])。

fib(N) 当 N == 0 -> 0 时;
fib(N) 当 (N < 3) 且 (N > 0) -> 1 时;
fib(N) 当 N > 0 -> fib(N-1) + fib(N-2) 时。

%% 在字符串格式中,现在将成为这段代码
StringCode = " -module(fib).\n -export([fib/1]). \nfib(N) 当 N == 0 -> 0;\n fib(N) 当 (N < 3) 和 (N > 0) -> 1;\n fib(N) 当 N > 0 -> fib(N-1) + fib(N-2) 时。\n"。

%% 然后客户端会将上面的这个字符串发送到服务器,服务器将
%% 动态加载代码并执行它

send_fib_code(Arg)-> {服务器注册名称,服务器节点}!{字符串,StringCode,fib,Arg}, 好的。 get_answer({fib,of,这,是,那}) -> io:format("~p 的斐波那契(来自服务器)是:~p~n",[This,That]). %%% 在服务器上 循环(服务器状态)-> 收到 {string,StringCode,Fib,Arg} 当 Fib == fib -> 尝试dynamic_compile:load_from_string(StringCode) 的 {模块,AnyMod} -> 答案 = AnyMod:fib(Arg), %%% 将答案发送回客户端 %%% 应该是异步的 %%% 因为渠道不同&不做 %% 客户端等待 rpc:call('client@domain.com',client,get_answer,[{fib,of,Arg,is,Answer}]) 抓住 _:_ -> error_logger:error_report(["无法从客户端动态编译和加载模块"]) 结尾, 循环(服务器状态); _ -> 循环(服务器状态) 结尾。

那段粗略的代码可以告诉你我想说的是什么。但是,请记住卸载所有不可用的动态模块。您还可以采用一种方法,让服务器在再次加载之前尝试检查此类模块是否已加载。我建议您不要复制并粘贴上面的代码。查看并理解它,然后编写可以完成这项工作的您自己的版本。
成功 !!!

  • 如果您想要递归 fun(),您可能会喜欢 Erlang y-combinator:http://bc.tech.coop/blog/070611.html (2认同)