Erlang中的简单增量

rlcwz9us  于 2022-12-08  发布在  Erlang
关注(0)|答案(1)|浏览(136)

我希望构建简单的Erlang逻辑,其中一个参与者维护它被调用多少次的计数。
例如,下面是演员(许多演员都可以是可能的):

-module(actor).
-export([do_work/0]).

do_work() ->
    increment = increment + 1

假设我调用actor(带有一些Pid:XYZ)5次,XYZ = 5,因为它被执行了5次。但是在Erlang中,变量是不可变的。所以如果我在第一次运行时执行increment++,我不能以增量存储新的结果,也不能执行increment = increment + 1。我如何维护计数,因为我不能动态地创建新的变量,比如说,increment_iteration_1 = increment + 1,然后执行increment_iteration_2 = increment1 + 1等等.....在代码中进行1000次迭代?

uidvcgyl

uidvcgyl1#

你的问题触及了Erlang和其他流行语言的主要区别。为了维护和更新Erlang中的一些状态--比如你例子中的计数器--你需要做一些具体的事情,我在下面描述。(其他的解决方案,比如使用数据库,我将跳过这里,因为我假设你想直接知道如何做状态维护)。
在Erlang中,你所称的 actor 被称为 process。是的,为了维护一个状态,你需要一个进程。你所展示的代码,虽然被命名为actor,但并不是一个进程。它只是一个模块,这意味着它只是一些代码。要使用一个进程,你需要启动它,保持它运行,并使用消息与它通信。这听起来可能很复杂,但是Erlang标准库提供了gen_server,它为您完成了大部分工作。
使用gen_server实作计数器的范例程式码如下所示:

-module(actor).
-behaviour(gen_server).
-export([do_work/0, init/1, handle_cast/2, handle_call/3]).

do_work() ->
    gen_server:cast(actor_server, do_work).

init(_Arguments) ->
    {ok, 0}.

handle_cast(do_work, Counter) ->
    {noreply, Counter + 1}.

handle_call(_Msg, _From, Counter) ->
    {noreply, Counter}.

现在,在代码中的某个地方,您需要使用

gen_server:start_link({local, actor_server}, actor, [], [])

然后,无论何时调用actor:do_work(),它都会递增计数器。
值得一提的几件事是:

  • actor是一个 callback 模块。Gen_server在内部执行繁重的工作,并在需要时从模块调用回调函数
  • init回调函数在进程启动时被调用一次。我在这里用它来初始化计数器。
  • 这个进程是 registered 的,名称是actor_server。当do_work在内部调用gen_server:cast时,它会向在actor_server名称下注册的进程发送一条消息。如果您需要几个进程分别执行同一个计数器,则需要更多的内务处理,我将在这里跳过。
  • handle_call部分(此处未使用)提供了从进程接收应答(例如更新的计数器)的功能。
  • 直接调用gen_server:start_link对于测试是很好的,但是在真实的代码中,您将有一个主管为您启动该过程

有关gen_server的更多信息,请参阅its documentation

相关问题