4

我最近完成了乔的书,非常喜欢它。从那时起,我开始使用 erlang 编写软实时应用程序,我不得不说我对 gen_server 的使用有点困惑。

我什么时候应该使用 gen_server 而不是简单的无状态模块?我将无状态模块定义如下: - 一个将其状态作为参数的模块(很像 ETS/DETS),而不是将其保留在内部(如 gen_server)

比如说发票管理器类型模块,它应该初始化并返回我随后传递给它的状态吗?SomeState = InvoiceManager:Init(), SomeState = InvoiceManager:AddInvoice(SomeState, AnInvoiceFoo)。

假设我需要发票管理器状态的多个实例(比如我的应用程序管理多个公司,每个公司都有自己的发票),如果他们每个人都有一个带有内部状态的 gen_server 来管理他们的发票,或者更适合简单地拥有无状态模块多于?

两者之间的界线在哪里?

(注意上面的发票管理例子就是这样,一个例子来说明我的问题)

4

5 回答 5

8

我真的不认为您可以在所谓的无状态模块和 gen_server 之间做出区分。在这两种情况下,都有一个递归接收循环,它至少在一个参数中携带状态。这个主循环处理请求,根据请求工作,并在必要时将结果发送回请求者。主循环很可能也会处理一些管理请求,这些请求可能不是主 API/协议的一部分。

不同之处在于 gen_server 抽象了主接收循环,并允许用户只编写实际的用户代码。它还将为您处理许多管理 OTP 功能。主要区别在于用户代码位于另一个模块中,这意味着您更容易看到通过状态。除非您实际上设法在一个大的接收循环中编写代码并且不调用其他函数来完成工作,否则没有真正的区别。

哪种方法更好在很大程度上取决于您需要什么。使用 gen_server 将简化您的代码并“免费”为您提供附加功能,但它可能更具限制性。自己动手会给你更多的力量,但你也会有更多的可能性把事情搞砸。它可能也快一点。你需要什么?

于 2009-10-24T23:05:29.167 回答
2

它在很大程度上取决于您的需求和应用程序设计。当您需要在进程之间共享状态时,您必须使用进程来保持此状态。那么gen_servergen_fsm或者其他gen_*是你的朋友。当您的应用程序不是并发的或者这种设计没有给您带来一些其他好处时,您可以避免这种设计。例如,将您的应用程序分解为进程将导致更简单的设计。在其他情况下,有时您可以选择单一流程设计并使用“无状态”模块来提高性能等。“无状态”模块是非常简单的无状态(纯功能)任务的最佳选择。gen_server通常是认为自然“过程”的最佳选择。当您想在进程之间共享某些东西时必须使用它(使用进程可能会受到可伸缩性或并发性的限制)。

于 2009-10-23T17:09:09.823 回答
1

在使用了这两种模型之后,我必须说使用提供的 gen_server 可以帮助我更轻松地保持结构化。我想这就是为什么它被包含在 OTP 工具堆栈中的原因: gen_server 是消除重复样板的好方法。

于 2009-10-23T14:51:28.743 回答
1

如果您在多个进程上共享状态,您可能应该使用 gen_server 并且如果状态只是一个进程的本地状态,那么无状态模块就可以了。

于 2009-10-23T14:57:57.453 回答
1

我想您的发票(或它们所代表的任何东西)应该是持久的,因此无论如何它们最终都会出现在 ETS/Mnesia 表中。如果是这样,您应该创建一个无状态模块,在其中放置用于访问发票表的 API。

于 2009-10-23T18:14:21.423 回答