<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
</head>
<body bgcolor="#ffffff" text="#000000">
Hi Joe:<br>
<br>
I have some question in my work now .<br>
<br>
this letter so quick!!<br>
<br>
于 2011/4/20 16:11, Joe Armstrong 写道:
<blockquote
cite="mid:BANLkTi=gtR2yjQKNEuJaHF+Wi8Sr111Vug@mail.gmail.com"
type="cite"><br>
<br>
<div class="gmail_quote">On Tue, Apr 19, 2011 at 6:19 PM, Dave
Challis <span dir="ltr"><<a moz-do-not-send="true"
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 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 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
moz-do-not-send="true"
href="mailto:dsc@ecs.soton.ac.uk" target="_blank">dsc@ecs.soton.ac.uk</a><br>
</div>
</div>
<div>
<div class="h5">
<mailto:<a moz-do-not-send="true"
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 moz-do-not-send="true"
href="mailto:dsc@ecs.soton.ac.uk" target="_blank">dsc@ecs.soton.ac.uk</a>
<mailto:<a moz-do-not-send="true"
href="mailto:dsc@ecs.soton.ac.uk" target="_blank">dsc@ecs.soton.ac.uk</a>><br>
_______________________________________________<br>
erlang-questions mailing list<br>
<a moz-do-not-send="true"
href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a>
<mailto:<a moz-do-not-send="true"
href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a>>
<div class="im">
<br>
<a moz-do-not-send="true"
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 class="h5">
Dave Challis<br>
<a moz-do-not-send="true"
href="mailto:dsc@ecs.soton.ac.uk" target="_blank">dsc@ecs.soton.ac.uk</a><br>
</div>
</div>
</blockquote>
</div>
<br>
<pre wrap="">
<fieldset class="mimeAttachmentHeader"></fieldset>
_______________________________________________
erlang-questions mailing list
<a class="moz-txt-link-abbreviated" href="mailto:erlang-questions@erlang.org">erlang-questions@erlang.org</a>
<a class="moz-txt-link-freetext" href="http://erlang.org/mailman/listinfo/erlang-questions">http://erlang.org/mailman/listinfo/erlang-questions</a>
</pre>
</blockquote>
<br>
<br>
<pre class="moz-signature" cols="72">--
Best Regards,
余超 YuChao <a class="moz-txt-link-abbreviated" href="mailto:UC:yuchao86@sina.cn">UC:yuchao86@sina.cn</a>
产品研发部 公共服务平台
电话:(8610)62676661
手机:13466539920 <a class="moz-txt-link-abbreviated" href="mailto:MSN:yuchao86@live.cn">MSN:yuchao86@live.cn</a>
地址:北京市海淀区北四环西路58号理想国际大厦15层22-2
___________________________________________
<a class="moz-txt-link-freetext" href="http://www.sina.com.cn">http://www.sina.com.cn</a> You're the one
新浪.北京 一切由你开始</pre>
</body>
</html>