Erlang: gen_server or my own custom server?
Asked Answered
C

5

5

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?

Coligny answered 3/12, 2009 at 12:56 Comment(7)
You have been very concerned about efficiency for the past few questions. Do you have any numbers of what the performance requirements are?Moult
Oh, and definitely go with gen_server until you can measure where your bottlenecks are.Moult
I don't have any numbers to quantize the performance requirements for the system now. This is an experimental system, so all I know for now is that the servers will have to handle an incredible volume of traffic. So I'm trying to be extra conscious about efficiency and optimize as much as possible.Coligny
@Christian, oh and will let you know when the system is ready for primetime, if you're interested :)Coligny
@ErJab: just post the URL of your blog entry announcing the service in your profile.Bamboo
@Bamboo Lights, camera, Pixza! I am working on a multi-player really realtime browser-based game called Pixza. And yes, we're using erlang for the backend. The game is now live at pixza.com . Let me know what you think.Coligny
Btw, it is a multi-player game, so only with 10 or more people playing it, it will be real fun. But you can look around otherwise.Coligny
C
10

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
Chichihaerh answered 3/12, 2009 at 14:30 Comment(1)
But you can add sys and proc_lib to make your simple loop OTP compatible, and get all the advantages listed above. See erlang.org/doc/design_principles/spec_proc.html and a good example from the book "scalability with eralang otp" cap. 10, github.com/francescoc/scalabilitywitherlangotp/blob/master/ch10/…Kuwait
B
10

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.

Bamboo answered 3/12, 2009 at 13:13 Comment(0)
C
10

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
Chichihaerh answered 3/12, 2009 at 14:30 Comment(1)
But you can add sys and proc_lib to make your simple loop OTP compatible, and get all the advantages listed above. See erlang.org/doc/design_principles/spec_proc.html and a good example from the book "scalability with eralang otp" cap. 10, github.com/francescoc/scalabilitywitherlangotp/blob/master/ch10/…Kuwait
Z
3

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.

Zingale answered 3/12, 2009 at 13:3 Comment(0)
S
2

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.
Substantialism answered 3/12, 2009 at 16:9 Comment(0)
I
2

I assume from your question that you are writing a more "permanent" server.

In general rolling your own server is more versatile and a little faster, if you get it right. But, and this is a big BUT:

  • You will have to do everything yourself, which increases the risk of errors!

  • If you want your server to be managed in the OTP way, which you probably do if you are building a robust system, then you will have to handle all that yourself as well. And get it right.

If I was doing a permanent server I would start out using gen_server and only fallback and roll my own if I run into serious difficulties in implementing what I need.

Short lived servers are another matter.

Intracranial answered 3/12, 2009 at 22:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.