It's not entirely clear to me what you want to do. I never understand 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 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 State<br>needed in your computation. State2 (returned by func2) is the continuation state of the server.<br>
ie the state the server will have after it has received the foo request, 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 four lines of<br>
code which define handle_call should return quickly, ie don't do much here, do the work in<br>do_something. handle call returns {noreply, State2} which means "don't 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 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 inside the client<br>
and request the data you need from the server, the server can spawn a 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 going on<br>
<br>Define promise and yield thusly:<br><br>promise(Fun) -> <br> S = self(), %% this self() is evaluated *inside* the current function<br> spawn(fun() -> <br> S ! {self(), Fun()} %% this self() is evaluated *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 promise to <br>
compute the value. The promise can be redeemed by calling yield. So we 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 other stuff.<br><br><br>The gen_server stuff above has just hidden what is essentially a promise and yield and<br>a bit of state trickery in a framework module - nothing tricky about 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><div class="gmail_quote">On Tue, Apr 19, 2011 at 10:58 AM, 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,<br>
I'm trying to work out the structure for a small bit of functionality in erlang. I've got a feeling there's an obvious solution, but I'm not experienced enough with the language sure what pattern to best follow...<br>
<br>
So far, I've got a server which implements the gen_server behaviour, a supervisor for it, and a module containing an API for interacting with it (using gen_server:call mostly).<br>
<br>
The server does a lot of work though, so blocks for a while until the call is finished.<br>
<br>
What I'd like to do, is create a new server process each time gen_server:call is invoked by a client, with each server terminating when it's done processing (but always leaving 1 server running).<br>
<br>
This means that clients using the API will have their request processes straight away, without having to wait for all the other 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, then send the client's call to this?<br>
* Should API calls go to the supervisor, and have it decide whether 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 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 pattern or some functionality I've missed?<br>
<br>
Thanks,<br><font color="#888888">
<br>
-- <br>
Dave Challis<br>
<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><br>
<a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
</font></blockquote></div><br>