5

我需要编写一个服务器,它将接收来自其他模块的指令并根据收到的指令采取行动。效率是我主要关心的问题。所以我使用gen_server还是编写自己的服务器。“我自己的服务器”是指:

-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().

所以要使用myserver,我可能会在启动时将进程注册到一个注册名称下,然后每个客户端都会使用这个 pid 向服务器发送消息。

那么我应该使用这种方法,还是使用这种gen_server行为来实现服务器?使用有什么好处gen_server吗?但是gen_server与 相比,使用会增加任何开销myserver吗?

4

5 回答 5

10

我也会去的gen_server。一旦你使用了这个设施,你就会学会欣赏它的价值。函数回调可能有点尴尬(例如handle_cast对于异步调用),但最终,您会习惯它。

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.

于 2009-12-03T13:13:34.660 回答
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
于 2009-12-03T14:30:08.483 回答
3

我会选择这样做,gen_server只是因为在各种情况下让它做正确的事情已经花了很多心思。它会处理难以正确处理的细节。我想gen_server可能会增加一些开销,但我已经停止提供性能建议。如果您真的有兴趣,请同时实施并测量速度,这是唯一确定的方法。

于 2009-12-03T13:03:23.150 回答
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.
于 2009-12-03T16:09:15.273 回答
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.

于 2009-12-03T22:20:38.060 回答