Если функция вычисления является автономной, т. Е. Не зависит от каких-либо других модулей или функций на клиенте C, то вам нужно сделать следующее: fun
(Функциональный Объекты). A fun
может быть отправлено по сети и применено удаленной машиной, а также fun
, отправитель встроил их адрес и способ получить ответ обратно. Таким образом, исполнитель может видеть только fun
, на который они могут или не могут дать аргумент, но внутри забавы отправитель принудительно вызвал метод, при котором ответом будет автоматически быть отправленным обратно. fun
- это абстракция очень многих задач в одной вещи, и ее можно перемещать в качестве аргументов.
На клиенте вы можете иметь такой код:
%% 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.
Таким образом, исполнителю задания не нужно знать, как отправить ответ обратно, Само задание приходит, зная, как оно отправит ответ на отправленное задание! . Я использовал этот метод отправки функциональных объектов по сети в нескольких проектах, это так здорово !!!
#### EDIT #####
Если у вас есть рекурсивная проблема, вы управляете рекурсией, используя funs
. Однако вам понадобится как минимум одна библиотечная функция на клиенте и / или сервере, чтобы помочь в рекурсивных манипуляциях. Создайте функцию, которая должна быть в пути кода клиента и сервера.
Другой вариант - динамически отправлять код с сервера на клиент, а затем использовать библиотеку: <a href="https://github.com/JacobVorreuter/dynamic_compile" rel="nofollow">Dynamic Compile erlang</a>
для загрузки и выполнения кода 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>
То, что мы видим выше, это фрагмент кода модуля, который динамически компилируется и загружается из строки. Если библиотека, обеспечивающая это, доступна на сервере и клиенте, то каждый объект может отправлять код в виде строки, а другой загружать и выполнять его динамически. Этот код может быть выгружен после использования. Давайте посмотрим на функцию Фибоначчи и как ее можно отправить и выполнить на сервере:
<b>%% This is the normal Fibonacci code which we are to convert into a string:</b>
-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).
<b>%% In String format, this would now become this piece of code</b>
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".
<b>%% Then the client would send this string above to the server and the server would <br>%% dynamically load the code and execute it</b><br>
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]).
<b>%%% At Server</b>
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.
Этот кусок грубого кода может показать вам, что я пытаюсь сказать. Однако вы не забудьте выгружать все неиспользуемые динамические модули. Также у вас может быть способ, которым сервер пытается проверить, загружался ли такой модуль уже перед его повторной загрузкой. Я советую вам не копировать и не вставлять приведенный выше код. Посмотрите на это и поймите это, а затем напишите свою собственную версию, которая может сделать эту работу.
успеха !!!