我需要编写一个服务器来接收来自其他模块的指令,并根据收到的指令采取措施。效率是我的主要关注点。所以我使用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
会增加任何开销吗?
答案 0 :(得分:10)
我也会选择gen_server
。一旦您使用了这个设施,您将学会欣赏它的价值。函数回调可能有点尴尬(例如handle_cast
用于异步调用)但最后,你会习惯它。
此外,我建议不要在没有做过一些测试的情况下进行“过早优化”。您可能不希望牺牲边际效率增益的可读性/可维护性。
答案 1 :(得分:10)
gen_server
的开销可以忽略不计,因为每个消息需要一些额外的函数调用(其中一个是动态的)。我认为你不应该在这个实施阶段考虑这个问题。你有没有改变主意,从gen_server
转移到你自己的服务器应该很简单。
与简单循环相比,gen_server
得到的是:
答案 2 :(得分:3)
我会选择gen_server
只是因为在各种情况下都做了正确的事情。它会处理难以理解的细节。我想gen_server
可能会增加一些开销,但我已停止提供性能建议。如果你真的有兴趣那么实现它们并测量速度,这是唯一可靠的方法。
答案 3 :(得分:2)
您也可以使用RabbitMQ背后的人员gen_server2。
这就像gen_server,除了以下调整(来自评论):
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.
答案 4 :(得分:2)
我从你的问题中假设你正在编写一个更“永久”的服务器。
总的来说,滚动你自己的服务器更通用,速度更快,如果你做对了。但是,这是大但是:
您必须自己做所有事情,这会增加出错的风险!
如果您希望以OTP方式管理服务器,如果您正在构建一个强大的系统,那么您可能会这样做,那么您也必须自己处理所有这些。并且做对了。
如果我正在使用永久性服务器,我会开始使用gen_server
并且只有在我实现我需要的时候遇到严重困难时才会回退并自己动手。
短暂的服务器是另一回事。