Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Erlang: gen_server or my own custom server?

I need to write a server that will receive instructions from other modules and take actions depending on the instructions received. Efficiency is my main concern. So do I use gen_server or do I write my own server. By "my own server" I mean something like:

-module(myserver).
-export([start/0, loop/0]).

start() ->
        spawn(myserver, loop, []).

loop() ->
   receive
        {From, Msg} -> %Do some action here... ;
        message2 -> %Do some action here...;
        message3 -> %Do some action here...;
        message4 -> %Do some action here...;
        .
        .
        .
        _-> ok
   end,
   loop().

So to use myserver, I will probably register the process under a registered name while starting it, and then each client will send messages to the server using this pid.

So should I use this method, or instead implement the server using the gen_server behaviour? Are there any advantages to using gen_server? But will using gen_server add any overhead, when compared to myserver?

like image 547
ErJab Avatar asked Dec 03 '09 12:12

ErJab


4 Answers

gen_server will have a negligible overhead compared to self-implemented servers, because it requires a few additional function calls per message (one of which is dynamic). I don't think you should consider this at this point of implementation. Did you changed your mind at any point, moving from gen_server to your own server should be straightforward.

What you get with gen_server compared to a simple loop is:

  • debugging (with sys)
  • SASL logging
  • hibernation support
  • code upgrade support
like image 165
Zed Avatar answered Oct 10 '22 09:10

Zed


I would go with gen_server as well. Once you've used this facility, you will learn to appreciate its value. The function callback can be a bit awkward (e.g. handle_cast for async calls) but in the end, you'll get used to it.

Furthermore, I would be advised not to engage in "premature optimization" without having done some testing. You probably don't want to sacrifice readibility/maintainability for marginal efficiency gains.

like image 36
jldupont Avatar answered Oct 10 '22 09:10

jldupont


I would go with the gen_server simply because so much thought has gone into making it do the right thing under various circumstances. It takes care of details that are difficult to get right. I imagine gen_server might add some overhead but I've stopped giving performance advice. If you're really interested then implement both and measure the speed, that's the only surefire way to find out.

like image 41
svenningsson Avatar answered Oct 10 '22 11:10

svenningsson


You can also use gen_server2 by the guys behind RabbitMQ.

It's like gen_server except for the following adjustments (from the comments):

1) the module name is gen_server2

2) more efficient handling of selective receives in callbacks
gen_server2 processes drain their message queue into an internal
buffer before invoking any callback module functions. Messages are
dequeued from the buffer for processing. Thus the effective message
queue of a gen_server2 process is the concatenation of the internal
buffer and the real message queue.
As a result of the draining, any selective receive invoked inside a
callback is less likely to have to scan a large message queue.

3) gen_server2:cast is guaranteed to be order-preserving
The original code could reorder messages when communicating with a
process on a remote node that was not currently connected.
like image 43
Eric Avatar answered Oct 10 '22 11:10

Eric