[erlang-questions] blocking vs non-blocking gen_tcp:accept()
Serge Aleynikov
saleyn@REDACTED
Sat Feb 16 16:53:49 CET 2008
In addition to Sean's good example, I'd like to say that while blocking
calls such as gen_tcp:accept/2 generally don't have anything to do with
performance issues, in a large distributed system they may introduce
undesired properties leading to a loss of predictive behavior. Say, if
you need to synchronize a restart of several nodes, upgrade mnesia
schema and transition process state to a new version of code in a hot
system then blocking calls surely complicate these tasks by quite a bit
as they may cause timeouts in other processes.
Using blocking calls in stand-alone components such as ejabberds and
YAWS may not be an issue at all up until you start integrating them in
larger systems with a central point of control.
Serge
Sean Hinde wrote:
> Telecom systems typically have to allow re-configuration on the fly of
> everything (e.g. by sending a reconf message to a process). They might
> also perform hearbeat monitoring of key processes. Both of these things
> are much easier if a process is not sitting in a long term blocking call.
>
> Sean
>
> On 16 Feb 2008, at 03:13, Samuel Tesla wrote:
>
>> When is it not an acceptable design?
>>
>> I can't imagine that it's performance. Both of the large examples of
>> TCP services that I've seen in Erlang (YAWS and ejabberd) use this
>> model, and they're both documented to handle very heavy loads and
>> perform very well.
>>
>> -- Samuel
>>
>> On Fri, Feb 15, 2008 at 8:25 PM, Serge Aleynikov <saleyn@REDACTED>
>> wrote:
>> The objective of the article was to show how to build a TCP server using
>> only non-blocking processes and relying on the network driver to deliver
>> events of interest to the application layer. Blocking processes for N
>> seconds as in the code below is not always an acceptable design.
>>
>> I also wish that the non-blocking prim_inet:accept/2 call was exposed to
>> the gen_tcp module. Perhaps this was an oversight rather than a
>> conscious decision?
>>
>> Serge
>>
>> Samuel Tesla wrote:
>> > Robin: Sorry if you got this twice, I realized just after I hit send
>> that I
>> > had only replied to you.
>> >
>> > It only blocks the Erlang process, I believe.
>> >
>> > I've been meaning to post some code examples about this.
>> >
>> > What's always bugged me about that article is that it relies on
>> prim_inet
>> > which is not guaranteed at all to remain the same across releases,
>> whereas
>> > gen_tcp is (or at least guaranteed to be squawked about). I've written
>> > several TCP servers for personal projects, and I have found that
>> there's no
>> > need to use anything but gen_tcp:accept (with a timeout).
>> >
>> > Here's an example of using gen_tcp:accept/2 in a gen_server that
>> operates
>> > similarly to the one in that walkthrough.
>> >
>> > %% BEGIN CODE %%
>> > -module(tcp_lister).
>> >
>> > -behaviour(gen_server).
>> >
>> > -export([start_link/3]).
>> > -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
>> > terminate/2, code_change/3]).
>> >
>> > -define(TCP_ACCEPT_TIMEOUT, 10000).
>> >
>> > -record(state, {
>> > listen, % listening socket
>> > sup % supervisor for client proxies
>> > }).
>> >
>> > start_link(Port, Opts, Sup) when is_integer(Port),
>> > is_list(Opts),
>> > is_atom(Sup) ->
>> > gen_server:start_link(?MODULE, [Port, Opts, Sup], []).
>> >
>> > init([Port, Opts, Sup]) ->
>> > {ok, Listen} = gen_tcp:listen(Port, Opts),
>> > State = #state{listen=Listen, sup=Sup},
>> > gen_server:cast(self(), accept),
>> > ?MODULE:accept(),
>> > {ok, State}.
>> >
>> > handle_call(Request, From, State) ->
>> > {stop, {unknown_call, {Request, From}}, State}.
>> >
>> > handle_cast(accept, State) ->
>> > #state{listen=Listen, sup=Sup} = State,
>> > case gen_tcp:accept(Listen, ?TCP_ACCEPT_TIMEOUT) of
>> > {ok, Socket} -> Sup:start_client(Socket);
>> > {error, timeout} -> ok
>> > end,
>> > gen_server:cast(self(), accept),
>> > {noreply, State};
>> > handle_cast(Msg, State) ->
>> > {stop, {unknown_cast, Msg}, State}.
>> >
>> > handle_info(Info, State) ->
>> > {stop, {unknown_info, Info}, State}.
>> >
>> > terminate(_Reason, _State) ->
>> > ok.
>> >
>> > code_change(_OldVsn, State, _Extra) ->
>> > {ok, State}.
>> >
>> > %% END CODE %%
>> >
>> > Then Sup:start_link/1 looks like this:
>> >
>> > %% BEGIN CODE %%
>> > start_client(Socket) ->
>> > {ok, Pid} = supervisor:start_child(?MODULE, []),
>> > gen_tcp:controlling_process(Socket, Pid),
>> > ok = client_module:set_socket(Pid, Socket),
>> > ok.
>> > %% END CODE %%
>> >
>> > And client_module:set_socket just lets the newly spawned process
>> know what
>> > it's socket is just like in the trapexit article.
>> >
>> > There's several things this code doesn't handle. It could get other
>> errors
>> > such as EMFILE or ENFILE from gen_tcp:accept/2. But in those cases the
>> > gen_server will blow up and get logged and the supervisor will do
>> something
>> > appropriate. There is a brief moment during which sockets will sit
>> idle in
>> > the buffer, but seriously, it's brief.
>> >
>> > The key thing here is that you're using gen_tcp:accept/2, so you
>> won't be
>> > blocking the process forever. That means that the process will
>> eventually
>> > loop through and check it's mailbox again and can handle all of the fun
>> > supervision-tree stuff gen_server does behind the scenes.
>> >
>> > Hope this helps!
>> >
>> > -- Samuel
>> >
>> > On Fri, Feb 15, 2008 at 2:16 PM, Robin <robi123@REDACTED> wrote:
>> >
>> >> Does gen_tcp:accept() block the entire OS thread or just the calling
>> >> erlang process?
>> >>
>> >> "One of the shortcomings of the gen_tcp module is that it only exports
>> >> interface to a blocking accept call." ->
>> >>
>> >>
>> http://www.trapexit.org/Building_a_Non-blocking_TCP_server_using_OTP_principles
>>
>> >>
>> >> Does the performance gain of non-blocking accept justify the added
>> >> complexity (finite state machine etc)?
>> >>
>> >> thanks,
>> >>
>> >> Robin
>> >> _______________________________________________
>> >> erlang-questions mailing list
>> >> erlang-questions@REDACTED
>> >> http://www.erlang.org/mailman/listinfo/erlang-questions
>> >>
>> >
>> >
>> >
>> ------------------------------------------------------------------------
>> >
>> > _______________________________________________
>> > erlang-questions mailing list
>> > erlang-questions@REDACTED
>> > http://www.erlang.org/mailman/listinfo/erlang-questions
>>
>>
>> _______________________________________________
>> erlang-questions mailing list
>> erlang-questions@REDACTED
>> http://www.erlang.org/mailman/listinfo/erlang-questions
>
>
More information about the erlang-questions
mailing list