<!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>