Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/flash/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/lua/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Erlang:将客户端进程/功能卸载到服务器?_Erlang_Distributed Computing_Hotswap - Fatal编程技术网

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

Erlang:将客户端进程/功能卸载到服务器?,erlang,distributed-computing,hotswap,Erlang,Distributed Computing,Hotswap,我的设想如下: 我有一个带有函数foo()的客户端C,它执行一些计算 我希望服务器S(它不知道foo())执行此函数,并将结果发送回客户端 我试图确定在Erlang中执行此操作的最佳方式。我正在考虑: 热代码交换-即在S中“升级”代码,使其具有函数foo()。执行并发送回客户端 以一种分布式的方式,在所有节点都被适当注册的情况下,按照S!C:foo()-用于将函数“发送”到进程/节点 还有其他我没有想到的方法(或语言特征)吗 谢谢你的帮助 如果您执行S!C:foo()它将从模块C计算客户端函

我的设想如下: 我有一个带有函数foo()的客户端C,它执行一些计算

我希望服务器S(它不知道foo())执行此函数,并将结果发送回客户端

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

  • 热代码交换-即在S中“升级”代码,使其具有函数foo()。执行并发送回客户端
  • 以一种分布式的方式,在所有节点都被适当注册的情况下,按照S!C:foo()-用于将函数“发送”到进程/节点
还有其他我没有想到的方法(或语言特征)吗

谢谢你的帮助

如果您执行
S!C:foo()
它将从模块
C
计算客户端函数
foo/1
,并将其结果发送到进程
S
。这看起来不像你想做的。你应该这样做:

% In client

call(S, M, F, A) ->
  S ! {do, {M, F, A}, self()},
  receive
    {ok, V} -> V
  end.

% In server

loop() ->
  receive
    {do, {M, F, A}, C} ->
      C ! {ok, apply(M, F, A)},
      loop()
  end.

但在实际场景中,您必须做更多的工作,例如标记您的客户端消息以执行选择性接收(
make_ref/0
),捕获服务器中的错误并将其发送回客户端,从客户端监视服务器以捕获服务器关闭,添加一些超时等。看看gen_server:call/2和rpc:call/4,5是如何实现的,这就是为什么有OTP可以让您免于大部分gotcha的原因。

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

%% somewhere in the client %% client runs on node() == 'client@domain.com' -module(client). -compile(export_all). -define(SERVER,{server,'server@domain.com'}). give_a_server_a_job(Number)-> ?SERVER ! {build_fun(),Number}. build_fun()-> FunObject = fun(Param)-> Answer = Param * 20/1000, %% computation here rpc:call('client@domain.com',client,answer_ready,[Answer]) end, FunObject. answer_ready(Answer)-> %%% use Answer for all sorts of funny things.... io:format("\n\tAnswer is here: ~p~n",[Answer]). %%% somewhere on the server %%% server runs on node() == 'server@domain.com' -module(server). -compile(export_all). start()-> register(server,spawn(?MODULE,loop,[])). loop()-> receive {Fun,Arg} -> Fun(Arg), %% server executes job %% job automatically sends answer back %% to client loop(); stop -> exit(normal); _ -> loop() end.

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

%% This is the normal Fibonacci code which we are to convert into a string: -module(fib). -export([fib/1]). fib(N) when N == 0 -> 0; fib(N) when (N < 3) and (N > 0) -> 1; fib(N) when N > 0 -> fib(N-1) + fib(N-2). %% In String format, this would now become this piece of code StringCode = " -module(fib).\n -export([fib/1]). \nfib(N) when N == 0 -> 0;\n fib(N) when (N < 3) and (N > 0) -> 1;\n fib(N) when N > 0 -> fib(N-1) + fib(N-2). \n". %% Then the client would send this string above to the server and the server would
%% dynamically load the code and execute it

send_fib_code(Arg)-> {ServerRegName,ServerNode} ! {string,StringCode,fib,Arg}, ok. get_answer({fib,of,This,is,That}) -> io:format("Fibonacci (from server) of ~p is: ~p~n",[This,That]). %%% At Server loop(ServerState)-> receive {string,StringCode,Fib,Arg} when Fib == fib -> try dynamic_compile:load_from_string(StringCode) of {module,AnyMod} -> Answer = AnyMod:fib(Arg), %%% send answer back to client %%% should be asynchronously %%% as the channels are different & not make %% client wait rpc:call('client@domain.com',client,get_answer,[{fib,of,Arg,is,Answer}]) catch _:_ -> error_logger:error_report(["Failed to Dynamic Compile & Load Module from client"]) end, loop(ServerState); _ -> loop(ServerState) end. %%这是我们要转换成字符串的普通斐波那契码: -模块(fib)。 -出口([fib/1])。 当N==0->0时的fib(N); 当(N<3)和(N>0)->1时fib(N); 当N>0->fib(N-1)+fib(N-2)时,fib(N)。 %%在字符串格式中,这将成为这段代码 StringCode=“-module(fib)。\n-导出([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”。 %%然后,客户端将向服务器发送上面的字符串,服务器将动态加载代码并执行它
%% 发送fib代码(Arg)-> {ServerRegName,ServerNode}!{string,StringCode,fib,Arg}, 好啊 得到答案({fib,of,This,is,That})-> io:format(~p的Fibonacci(来自服务器)是:~p~n,[This,That])。 %%%服务器端 循环(服务器状态)-> 接收 {string,StringCode,Fib,Arg}当Fib==Fib-> 尝试动态编译:从的字符串(StringCode)加载 {模块,AnyMod}-> 答案=AnyMod:fib(Arg), %%%将答案发送回客户机 %%%应该是异步的 %%%因为渠道不同&不是制造的 %%客户端等待 rpc:call('client@domain.com,客户机,get_-answer,[{fib,of,Arg,is,answer}] 抓住 _:\->错误\u记录器:错误报告([“未能从客户端动态编译和加载模块”]) 完,, 循环(服务器状态); _->循环(服务器状态) 结束。
这段粗略的代码可以告诉你我想说什么。但是,请记住卸载所有不可用的动态模块。此外,您还可以使用一种方式,服务器尝试在再次加载模块之前检查该模块是否已加载。我建议您不要复制和粘贴上述代码。看看它,理解它,然后写你自己的版本,可以做这项工作<成功

@Muzayya Joshua谢谢,这个回答很有帮助。注意:在客户端代码中的rpc:call后面有一个额外的逗号。如果我想向服务器发送一个递归函数,以斐波那契为例,该怎么办?或者,如果我没有一个自包含函数,并且我想将整个调用堆栈移动到服务器上,该怎么办?感谢您的帮助。如果您想要递归fun(),您可能需要一个Erlang y-combinator:@Muzayya Joshua参考您的原始代码/回答:如果客户端和服务器从同一目录运行,传递fun就可以了。然而,若客户机和服务器不在同一个目录中(现实场景),我会在节点的进程中出错server@...'退出值:{unde,[{#Fun,[5]},{server,loop,0}}}我的问题:服务器似乎正在寻找执行函数的客户端。为什么会发生这种情况?如果这是一个错误,那就意味着你依赖于游戏中的另一个模块。乐趣不是自包含的,如考虑这2个功能:<代码>乐趣(X)> 2 + X结束< /代码>和<代码>乐趣(X)-> X+某个模块:FUNC(X)结束< /代码>。后者不是自包含的乐趣,因此无论发送到哪里,模块
某些模块必须在代码路径中,但前者的乐趣将在任何地方执行,即使在远程机器上也是如此。
%% This is the normal Fibonacci code which we are to convert into a string:

-module(fib).
-export([fib/1]).

fib(N) when N == 0 -> 0;
fib(N) when (N < 3) and (N > 0) -> 1;
fib(N) when N > 0 -> fib(N-1) + fib(N-2).

%% In String format, this would now become this piece of code
StringCode = " -module(fib).\n -export([fib/1]). \nfib(N) when N == 0 -> 0;\n fib(N) when (N < 3) and (N > 0) -> 1;\n fib(N) when N > 0 -> fib(N-1) + fib(N-2). \n".

%% Then the client would send this string above to the server and the server would 
%% dynamically load the code and execute it

send_fib_code(Arg)-> {ServerRegName,ServerNode} ! {string,StringCode,fib,Arg}, ok. get_answer({fib,of,This,is,That}) -> io:format("Fibonacci (from server) of ~p is: ~p~n",[This,That]). %%% At Server loop(ServerState)-> receive {string,StringCode,Fib,Arg} when Fib == fib -> try dynamic_compile:load_from_string(StringCode) of {module,AnyMod} -> Answer = AnyMod:fib(Arg), %%% send answer back to client %%% should be asynchronously %%% as the channels are different & not make %% client wait rpc:call('client@domain.com',client,get_answer,[{fib,of,Arg,is,Answer}]) catch _:_ -> error_logger:error_report(["Failed to Dynamic Compile & Load Module from client"]) end, loop(ServerState); _ -> loop(ServerState) end.