<br><br><div class="gmail_quote">On Tue, Apr 19, 2011 at 6:19 PM, Dave Challis <span dir="ltr"><<a href="mailto:dsc@ecs.soton.ac.uk">dsc@ecs.soton.ac.uk</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
Hi Joe,<br>
Fantastic, that's pretty much exactly what I was after.  I didn't realise I could send a {noreply, X} from a handle_call, and defer the actual reply from a spawned process.<br>
<br>
The pure erlang version makes it clear what's going on too - gen_server is still a bit of a black box to me I'm afraid.<br></blockquote><div><br>Oh dear - this frightens me - I've started a new thread to explain just exactly how simple the<br>
gen_server is - pleas read it<br> </div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<br>
The gen_server I'm using is a wrapper around a C utility which does some parsing (using erlang's port mechanism), and then returns the parsed data to the original function caller.<br>
<br></blockquote><div><br>Just to satisfy my curiosity,  why C? did you try this in pure Erlang first?<br><br><br>/Joe<br><br> </div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">

I figured that by having the port initialised when the gen_server process is started, it could respond to client requests right away, rather than being spawned upon request.<br>
<br>
I was also thinking that by having the C program and port set up at server start time, then any startup errors from it would be caught then, rather than everything appearing to be ok until a client request was made.<br>
<br>
Thanks,<br>
Dave<div><div></div><div class="h5"><br>
<br>
On 19/04/11 16:11, Joe Armstrong wrote:<br>
</div></div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;"><div><div></div><div class="h5">
It's not entirely clear to me what you want to do. I never understand<br>
why people use gen_servers<br>
for everything, pure Erlang is often easier :-)<br>
<br>
I assume you want to delegate the response in the server (ie get some<br>
other process than the<br>
gen server to do the work, since this takes a long time)<br>
<br>
One way to do this is like this:<br>
<br>
Write a client stub like this:<br>
<br>
foo(X) -><br>
     gen_server:call(?Mod, {foo, X}).<br>
<br>
<br>
Write a gen_server handle call method like this:<br>
<br>
handle_call({foo, X}, From, State) -><br>
     State1 = func1(X, State),<br>
     State2 = func2(X, State),<br>
     spawn_link(fun() -> do_something(State1, X, From) end),<br>
     {noreply, State2}.<br>
<br>
do_something(State, X, From) -><br>
     Reply = func3(X, State),<br>
     gen_server:reply(From, Reply).<br>
<br>
here I've assumed func1 returns State1 and that State1 is some subset of<br>
State<br>
needed in your computation. State2 (returned by func2) is the<br>
continuation state of the server.<br>
ie the state the server will have after it has received the foo request,<br>
but before the delegated function<br>
has replied. You'll have to write func1 and func2 yourself.<br>
<br>
do_something is the delegated function that might take a long time. The<br>
four lines of<br>
code which define handle_call should return quickly, ie don't do much<br>
here, do the work in<br>
do_something. handle call returns {noreply, State2} which means "don't<br>
reply to the client<br>
but continue with state State2.<br>
<br>
do_something works in parallel with the server and when it has finished<br>
calls gen_server:reply/2<br>
and at this point the client stub routine  foo/1 will return.<br>
<br>
This is only one way of doing this. You could do the complex calculation<br>
inside the client<br>
and request the data you need from the server, the server can spawn a<br>
deligate (as above).<br>
You can use a shared ets table and so on.<br>
<br>
if you were to do this in pure erlang it might be easier to see what's<br>
going on<br>
<br>
Define promise and yield thusly:<br>
<br>
promise(Fun) -><br>
       S = self(),                             %% this self() is<br>
evaluated *inside* the current function<br>
       spawn(fun() -><br>
                      S ! {self(), Fun()}    %% this self() is evaluated<br>
*inside* the spawned function<br>
                  end).<br>
<br>
yield(Promise) -><br>
      receive<br>
           {Promise, Result} -> Result<br>
      end.<br>
<br>
promise takes a Fun argument and returns a promise. The promise is a<br>
promise to<br>
compute the value. The promise can be redeemed by calling yield. So we<br>
can write code like this:<br>
<br>
P = promise(fun() -> fib(40) end),<br>
.... do some other stuff that takes a while ...<br>
Val = yield(Promise)<br>
<br>
So we compute fib(40) which takes a long time in parallel with some<br>
other stuff.<br>
<br>
<br>
The gen_server stuff above has just hidden what is essentially a promise<br>
and yield and<br>
a bit of state trickery in a framework module - nothing tricky about<br>
about it at all.<br>
<br>
Given promise and yield and a dash of list comprehensions we can write<br>
fun stuff like:<br>
<br>
parmap(F, L) -><br>
      Promises = [promise(fun() -> F(I) end || I <- L],<br>
      [yield(I) || I <- Promises].<br>
<br>
which is a parallel mapping function.<br>
<br>
Hope this helps<br>
<br>
/Joe<br>
<br>
<br>
<br>
On Tue, Apr 19, 2011 at 10:58 AM, Dave Challis <<a href="mailto:dsc@ecs.soton.ac.uk" target="_blank">dsc@ecs.soton.ac.uk</a><br></div></div><div><div></div><div class="h5">
<mailto:<a href="mailto:dsc@ecs.soton.ac.uk" target="_blank">dsc@ecs.soton.ac.uk</a>>> wrote:<br>
<br>
    Hi,<br>
    I'm trying to work out the structure for a small bit of<br>
    functionality in erlang.  I've got a feeling there's an obvious<br>
    solution, but I'm not experienced enough with the language sure what<br>
    pattern to best follow...<br>
<br>
    So far, I've got a server which implements the gen_server behaviour,<br>
    a supervisor for it, and a module containing an API for interacting<br>
    with it (using gen_server:call mostly).<br>
<br>
    The server does a lot of work though, so blocks for a while until<br>
    the call is finished.<br>
<br>
    What I'd like to do, is create a new server process each time<br>
    gen_server:call is invoked by a client, with each server terminating<br>
    when it's done processing (but always leaving 1 server running).<br>
<br>
    This means that clients using the API will have their request<br>
    processes straight away, without having to wait for all the other<br>
    calls to the server to finish.<br>
<br>
    I can't quite figure out where to place the logic for doing this though.<br>
<br>
    * Should the API module ask the supervisor to spawn a new child,<br>
    then send the client's call to this?<br>
    * Should API calls go to the supervisor, and have it decide whether<br>
    to spawn new servers or send the call to an existing one?<br>
    * Or should each server take care of telling the supervisor to spawn<br>
    a new child, and pass the call request to the newly spawned one?<br>
<br>
    Is this a sensible approach in general, or is there an obvious<br>
    pattern or some functionality I've missed?<br>
<br>
    Thanks,<br>
<br>
    --<br>
    Dave Challis<br></div></div>
    <a href="mailto:dsc@ecs.soton.ac.uk" target="_blank">dsc@ecs.soton.ac.uk</a> <mailto:<a href="mailto:dsc@ecs.soton.ac.uk" target="_blank">dsc@ecs.soton.ac.uk</a>><br>
    _______________________________________________<br>
    erlang-questions mailing list<br>
    <a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a> <mailto:<a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a>><div class="im">
<br>
    <a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
<br>
<br>
</div></blockquote>
<br>
<br>
-- <br><div><div></div><div class="h5">
Dave Challis<br>
<a href="mailto:dsc@ecs.soton.ac.uk" target="_blank">dsc@ecs.soton.ac.uk</a><br>
</div></div></blockquote></div><br>