我已经弄明白了二郎式的循环:尾递归,其函数采用所有“不变的变量”:
%% does something, 80 bytes at a time
loop(Line, File) -> loop(Line, File, 0).
loop(Line, File, Count) ->
do_something(Line, Count),
case file:read(File, 80) of
{ok, Line2} -> loop(Line2, File, Count + 1);
eof -> file:close(File);
{error, Reason} -> {error, Reason}
end.
但是,在Erlang中增加计数器的最佳方式是什么?在大多数编程语言中,计数的方式是增加一个变量(即count += 1;
)。Erlang的变量不变,所以我们必须有创造性。幸运的是,我们有选择...
我们可以用函数传递Counter变量,并在每次函数调用时递增它。我们可以使用进程字典来存储计数,使用get
和put
来递增它。我们可以使用ETS,进程的本地数据存储。我们可以使用计数器进程(!!!):
loop(Count) ->
receive
{ incr } ->
loop(Count + 1);
{ report, To } ->
To ! { count, Count },
loop(Count)
end.
incr(Counter) ->
Counter ! { incr }.
get_count(Counter) ->
Counter ! { report, self() },
receive
{ count, Count } -> Count
end.
我相信还有其他的方法,这取决于作用域。在Erlang中增加变量的“最佳实践”是什么?
5条答案
按热度按时间holgip5t1#
不要使用进程字典。
您所期望的“normal”循环(即
for
循环或do while
)通常在Erlang中的递归函数中实现,因此如果您要递增“normal”计数器,请在函数调用中执行,就像您在顶部显示的那样。不要使用进程字典。
如果您没有注意到,请允许我指出您不应该使用过程字典。
inn6fuwd2#
这完全取决于你使用计数器的目的。任何全局性的东西,比如q system处理的消息数,都应该使用ets:update_counter。如果不是全局性的,我通常就把它包含在参数中,就像你展示的那样。
ssgvzors3#
考虑以下Erlang中for循环的实现:
F
是一个函数,可用于保存I
到Max
值的结果。qf9go6mv4#
递增计数器的标准方法和你的第一个例子一样。通过在调用中添加一个变量并递增它。我认为你会因为缺少for循环和更新值的可能性而感到困惑。
请注意:
编译为(或多或少)与(在伪代码中)相同的内容:
如果你想累积结果,也有办法做到这一点。
您可以使用lists软件包或自己累积结果:
或者根据你的例子类似的东西。
编辑:返回Count作为返回值的一部分,因为它似乎很重要。
ftf50wuq5#
As of Erlang/OTP 21.2 (released in December 2018), you can use the
counters
module . The documentation sums it up well:This module provides a set of functions to do operations towards shared mutable counter variables. The implementation does not utilize any software level locking, which makes it very efficient for concurrent access. The counters are organized into arrays with the following semantics:
atomics
orwrite_concurrency
. Theatomics
counters have good allround performance with nice consistent semantics whilewrite_concurrency
counters offers even better concurrent write performance at the expense of some potential read inconsistencies. Seenew/2
.For example, let's create a counter, increment it by 7, and check the value:
So where do you store the counter reference, if more than one process needs access to it? You can use
persistent_term
for that, also added in Erlang/OTP 21.2:Note that
persistent_term
should only be used for values that seldom or never change. You would presumably create the counter when your application start, store the reference as a persistent term, and then access it while the application is running.