【问题标题】:Erlang gen_server vs stateless moduleErlang gen_server vs 无状态模块
【发布时间】:2010-12-09 11:53:14
【问题描述】:

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

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

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

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

两者之间的界限在哪里?

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

【问题讨论】:

  • 请注意,代码示例中的原子(模块和函数名称)应以非大写字母开头。

标签: erlang erlang-otp


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-01-22
            • 2011-06-18
            • 2011-08-09
            • 2014-11-09
            • 2016-01-25
            • 2011-10-08
            • 2016-08-09
            相关资源
            最近更新 更多