在Erlang中计数(如何增加变量?)
我已经找到了Erlang风格的循环:带函数的尾部递归,它接受所有“不变的变量”: 但是,在Erlang中增加计数器的最佳方法是什么?在大多数编程语言中,计数的方式是通过增加一个变量(即,在Erlang中计数(如何增加变量?),erlang,Erlang,我已经找到了Erlang风格的循环:带函数的尾部递归,它接受所有“不变的变量”: 但是,在Erlang中增加计数器的最佳方法是什么?在大多数编程语言中,计数的方式是通过增加一个变量(即,count+=1;)。Erlang的变量是不变的,所以我们必须有创造性。幸运的是,我们有选择 我们可以在函数中传递一个计数器变量,并在每次函数调用中递增它。我们可以使用流程字典来存储计数,并使用get和put来增加计数。我们可以使用ETS,即进程的本地数据存储。我们可以使用计数器进程(!!!): 我相信也有其他方
count+=1;
)。Erlang的变量是不变的,所以我们必须有创造性。幸运的是,我们有选择
我们可以在函数中传递一个计数器变量,并在每次函数调用中递增它。我们可以使用流程字典来存储计数,并使用get
和put
来增加计数。我们可以使用ETS,即进程的本地数据存储。我们可以使用计数器进程(!!!):
我相信也有其他方法,这取决于范围。在Erlang中递增变量的“最佳实践”是什么?这完全取决于您使用计数器的目的。任何像q系统处理的消息数量这样的全局性数据都应该使用ets:update\u计数器。如果它不是全局的,我通常只将其包含在您显示的参数中。不要使用流程字典 您期望的“正常”循环(即
for
循环或do while
)通常在Erlang中的递归函数中实现,因此,如果要递增“正常”计数器,请在函数调用中执行它,就像显示在顶部一样
不要使用流程字典
如果您没有注意到,我可以指出您不应该使用流程字典。增加计数器的标准方法与您的第一个示例相同。通过向调用中添加变量并使其递增。我认为,由于缺少for循环和更新值的可能性,您会感到困惑 请注意:
repeat(Times) when Times >= 0 -> repeat(0, Times).
repeat(Times, Times) -> done;
repeat(N, Times) ->
do_a_side_effect,
repeat(N + 1, Times).
编译为(或多或少)与(在伪代码中)相同的内容:
或者类似的例子
编辑:返回的计数也是返回值的一部分,因为它似乎很重要。考虑一下Erlang中for循环的实现:
for( Max, Max, F ) -> [ F(Max) ];
for( I, Max, F ) -> [ F(I) | for( I+1, Max, F ) ].
F
是一个函数,您可以通过该函数将值I
的结果保存到Max
自Erlang/OTP 21.2(2018年12月发布)起,您可以使用。文件很好地总结了这一点:
此模块提供一组函数,用于对共享的可变计数器变量执行操作。该实现不使用任何软件级锁定,这使得它对并发访问非常有效。计数器被组织成具有以下语义的数组:
- 计数器是64位有符号整数
- 计数器在溢出和下溢操作时环绕
- 计数器初始化为零
- 写操作保证原子性。从单个写入操作中看不到中间结果
- 可以使用选项
或atomics
创建两种类型的计数器阵列。write\u concurrency
计数器具有良好的全面性能和良好的一致性语义,而atomics
计数器提供了更好的并发写入性能,但代价是一些潜在的读取不一致性。请参见write\u并发
新建/2
- 计数器数组的索引是基于一个的。大小为N的计数器数组包含索引为1到N的N个计数器
> MyCounterRef = counters:new(1, [atomics]).
{atomics,#Ref<0.3460962489.1601830917.24209>}
> counters:add(MyCounterRef, 1, 7).
ok
> counters:get(MyCounterRef, 1).
7
请注意,
persistent\u term
应仅用于很少或从未更改的值。您可能会在应用程序启动时创建计数器,将引用存储为永久术语,然后在应用程序运行时访问它。如果没有用例,这个问题就没有太大意义。您可以执行lists:foldl
对列表中的内容进行计数(或筛选+长度)。如果你在计算gen_服务器的调用数,你可以很容易地用服务器的状态来计算。我已经错过了PHP。。。静态$i$i++;另外,不要使用流程字典,但奇怪的是,在Erlang/OTP发行版中,几乎每个应用程序都使用流程字典。像inets
。或orber
。或docbuilder
。或ic
。或megaco
。或tv
。或cosNotification
。或eunit
。或reltool
。或编译器
。或erts
。或测试服务器
。或appmon
。或者ssh
。或调试器
。或内核
。或gs
。或os\u mon
。或pman
。或stdlib
。或percept
。或xmerl
。或asn1
。或mnesia
。或普通测试
。或parsetools
。或透析器
。或如果社区继续关注这条消息,那么更容易相信“无流程字典”的模因。一般规则是“如果你想知道是否应该使用流程字典,你就不应该使用它”和“你会知道什么时候需要它”。公平地说,虽然有有效的流程字典使用,据我所知,它们中的大多数与“递增变量”无关,而是与“存储流程元数据”有关。哦,我同意,我给出了糟糕的建议。我甚至不会考虑使用过程字典来增加变量。我只是觉得“不要使用流程字典”这句无意识的咒语很愚蠢,因为Erlang的核心发行版及其附带的所有lib都广泛使用了它。你的措辞好多了。“如果你想知道答案是否定的”和“你会知道什么时候你需要它”更有意义。
repeat(Times) ->
while (N < Times) {
do_a_side_effect
N++
}
return done
loop(File) ->
{ok, Fd} = file:open(File),
loop(Fd, 0, []).
loop(Fd, Count, Acc) ->
case file:read(Fd, 80) of
{ok, Line} ->
Result = do_something(Line, Count),
loop(Fd, Count + 1, [Result | Acc]);
eof ->
file:close(File),
{Count, lists:reverse(Acc)};
{error, Reason} -> {error, Reason}
end.
for( Max, Max, F ) -> [ F(Max) ];
for( I, Max, F ) -> [ F(I) | for( I+1, Max, F ) ].
> MyCounterRef = counters:new(1, [atomics]).
{atomics,#Ref<0.3460962489.1601830917.24209>}
> counters:add(MyCounterRef, 1, 7).
ok
> counters:get(MyCounterRef, 1).
7
> persistent_term:put(my_counter_ref, MyCounterRef).
ok
> counters:add(persistent_term:get(my_counter_ref), 1, 9).
ok
> counters:get(persistent_term:get(my_counter_ref), 1).
16