計算機能が自己完結型である場合、つまりクライアントCの他のモジュールや関数に依存しない場合は、fun
(機能オブジェクト)が必要です。 A fun
は、ネットワークを介して送信し、リモートマシンによって適用することができ、その側にはfun
と入力します。送信者は、アドレスと返信方法を埋め込みます。したがって、実行者は、引数を与えても与えなくても、fun
しか見ることができませんが、送信者は答えが自動的に返される方法を強制しています。 fun
は、1つの事の中で非常に多くのタスクを抽象化しており、引数として移動することができます。クライアントで
、あなたがこのようなコード持つことができます。
%% somewhere in the client
%% client runs on node() == '[email protected]'
-module(client).
-compile(export_all).
-define(SERVER,{server,'[email protected]'}).
give_a_server_a_job(Number)-> ?SERVER ! {build_fun(),Number}.
build_fun()->
FunObject = fun(Param)->
Answer = Param * 20/1000, %% computation here
rpc:call('[email protected]',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() == '[email protected]'
-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.
を、ジョブエグゼキュータは戻って送信する方法を知っている必要はありません返信、仕事自体は、仕事を送ったが、答えを返す方法を知って来る!。私はいくつかのプロジェクトでネットワークを介して機能オブジェクトを送信するこの方法を使用しました。
####あなたは再帰的な問題を持っている場合は、あなたがfuns
を使用して再帰を操作
##### EDIT。ただし、再帰的操作を支援するには、クライアントおよび/またはサーバーで少なくとも1つのライブラリ関数が必要です。クライアントとサーバーのコードパスにある関数を作成します。
もう1つの方法は、サーバからクライアントへコードを動的に送信し、次にライブラリを使用することです。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> dynamic_compile:load_from_string(String).
{module,add}
3> add:add(2,5).
7
4>
上記の内容は、文字列からコンパイルされ、動的にロードされるモジュールコードです。これを可能にするライブラリがサーバーとクライアントで利用可能な場合、各エンティティはコードを文字列として送信し、コードを別のエンティティで動的にロードして実行できます。このコードは、使用後にアンロードすることができます。
%% 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('[email protected]',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.
ラフコードの一部が言うしようとしているものをお見せできること:フィボナッチ機能を見て、どのようにサーバーに送信され、実行することができます。ただし、使用できないすべての動的モジュールをアンロードすることを忘れないでください。また、サーバーは、そのようなモジュールがすでにロードされているかどうかをチェックしてから、再度ロードすることもできます。上記のコードをコピー&ペーストしないことをお勧めします。それを見てそれを理解してから、自分の仕事をすることができるバージョンを書いてください。
成功!
@ Muzayya-Joshuaありがとう、この回答は非常に役に立ちました。注:クライアントコードでrpc:callの後に余分なカンマがあります。サーバーに再帰関数を送信する場合は、たとえばフィボナッチを使用しますか?あるいは、自己完結型の関数を持たず、呼び出しスタック全体をサーバーに移動したいのですが?すべての助けをありがとう。 – Eitan
再帰的なfun()をしたい場合は、Erlang y-combinatorが好きかもしれません:http://bc.tech.coop/blog/070611.html – MatthewToday
** @ Muzayya-Joshua **オリジナルのコードを参照してください/ answer:クライアントとサーバーが同じディレクトリから実行されている場合、Funを渡すとうまく動作します。しかし、クライアントとサーバが同じディレクトリに存在しない場合(現実的なシナリオ)、出口値を持つノード 'server @ ...'上のプロセス<0.39.0>の_Errorを取得します:{undef、[{Fun、[5 ]}、{サーバー、ループ、0}]} _ **私の質問:サーバーは、クライアントがその機能を実行するのを探しているようです。 ** –
Eitan