Erlang:gen_server 还是我自己的自定义服务器?

Posted

技术标签:

【中文标题】Erlang:gen_server 还是我自己的自定义服务器?【英文标题】:Erlang: gen_server or my own custom server? 【发布时间】:2010-12-22 19:41:48 【问题描述】:

我需要编写一个服务器来接收来自其他模块的指令并根据收到的指令采取行动。效率是我主要关心的问题。我是使用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 有什么好处吗?但是与myserver 相比,使用gen_server 会增加任何开销吗?

【问题讨论】:

前几个问题你一直很关心效率。你有什么性能要求的数字吗? 哦,一定要使用 gen_server,直到你能测量出你的瓶颈在哪里。 我现在没有任何数字来量化系统的性能要求。这是一个实验性系统,所以我现在只知道服务器必须处理难以置信的流量。所以我试图更加注重效率并尽可能优化。 @Christian,哦,如果您有兴趣,会在系统准备好黄金时段时通知您:) @ErJab:只需在您的个人资料中发布您宣布该服务的博客条目的 URL。 【参考方案1】:

gen_server 与自行实现的服务器相比,开销可以忽略不计,因为它需要对每条消息进行一些额外的函数调用(其中一个是动态的)。我认为您在实施时不应该考虑这一点。您是否在任何时候改变了主意,从 gen_server 转移到您自己的服务器应该很简单。

与简单循环相比,gen_server 得到的结果是:

调试(使用 sys) SASL 日志记录 休眠支持 代码升级支持

【讨论】:

但是您可以添加 sys 和 proc_lib 以使您的简单循环 OTP 兼容,并获得上面列出的所有优点。请参阅erlang.org/doc/design_principles/spec_proc.html 和“使用eralang otp 的可扩展性”一书中的一个很好的例子。 10、github.com/francescoc/scalabilitywitherlangotp/blob/master/ch10/…【参考方案2】:

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

此外,建议我不要在未进行一些测试的情况下进行“过早优化”。您可能不想为了边际效率收益而牺牲可读性/可维护性。

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

您也可以使用 RabbitMQ 背后的人的gen_server2。

它类似于 gen_server,除了以下调整(来自 cmets):

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.

【讨论】:

【参考方案5】:

我从您的问题中假设您正在编写一个更“永久”的服务器。

一般来说,如果你做对了,你自己的服务器会更通用,速度也更快。但是,这是一个但是:

您必须自己做所有事情,这会增加出错的风险!

如果您希望以 OTP 方式管理您的服务器,如果您正在构建一个强大的系统,您可能会这样做,那么您也必须自己处理所有这些。做对了。

如果我正在做一个永久服务器,我会开始使用gen_server,并且只有在我在实现我需要的东西时遇到严重困难时才会回退并滚动自己的服务器。

短期服务器是另一回事。

【讨论】:

以上是关于Erlang:gen_server 还是我自己的自定义服务器?的主要内容,如果未能解决你的问题,请参考以下文章

难以理解 Erlang Gen_Server 架构

何时在 Erlang/OTP 应用程序中使用 gen_server

Erlang 源码分析之 Gen_Server

Erlang:无法创建 gen_server:call()

Erlang:如何在主管中正确调度带有 start_child 的 gen_server 并调用 API

ERLang OTP gen_server:call() 失败