在 Erlang 中计数(如何递增变量?)
我已经弄清楚了 Erlang 风格的循环:带有采用所有“不变变量”的函数的尾递归:
%% 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 中增加变量的“最佳实践”是什么?
I've figured out the Erlang-style loops: tail-recursion with functions that take all the "variables that don't vary":
%% 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.
But, what is the best way to increment a counter in Erlang? In most programming languages, the way you count things is by incrementing a variable (ie. count += 1;
). Erlang's variables don't vary, so we have to be creative. Fortunately, we have options...
We can pass a Counter variable with our functions, and increment it with each function call. We can use the process dictionary to store a count, and get
and put
to increment it. We can use ETS, the local data storage for processes. We can use a counter process (!!!):
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.
I'm sure there are other ways too, depending on the scope. What's considered "best practice" for incrementing a variable in Erlang?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
不要使用进程字典。
您所期望的“正常”循环(即
for
循环或do while
)通常是在 Erlang 中的递归函数中实现的,因此如果您递增“正常”循环, ' 在函数调用中计数器执行此操作,就像您显示在顶部一样。不要使用进程字典。
如果您错过了,我可以指出您不应该使用流程字典吗?
Don't use the process dictionary.
The 'normal' loop that you are expecting (ie a
for
loop or ado while
) is usually implemented in a recursive function in Erlang so if you are incrementing a 'normal' counter do it in the function calls like you show up top.Don't use the process dictionary.
In case you missed, can I just point out that you should not use the process dictionary.
这完全取决于您使用计数器的目的。任何全局的东西,比如 q 系统处理的消息数量,都应该使用 ets:update_counter。如果它不是全局的,我通常只是将其包含在您所示的参数中。
It all depends on what you are using the counter for. Anything global like the number of messages handled by q system should use ets:update_counter. If it is not global I usually just include it in the parameters like you showed.
考虑一下 Erlang 中 for 循环的实现:
F
是一个函数,您可以通过它保存值I
到Max
的结果。Consider this implementation of a for loop in Erlang:
F
is a function from which you can save results for valuesI
toMax
.递增计数器的标准方法如第一个示例所示。通过向调用添加变量并递增它。我认为您会因为缺少 for 循环和更新值的可能性而感到困惑。
请注意:
编译为(或多或少)与(伪代码中)相同的内容:
如果您想累积结果,也有一些方法可以做到这一点。
使用列表包或自己累积结果:
或者根据您的示例进行类似的操作。
编辑:返回 Count 也作为返回值的一部分,因为它似乎很重要。
The standard way of incrementing a counter is as in your first example. By adding a variable to the call and incrementing it. I think that you get confused by the lack of for loops and possibility to update values.
Note that:
compiles to (more or less) the same thing as (in pseudo code):
If you want to accumulate the result there are ways to do that as well.
Either use the lists package or accumulate the result yourself:
Or something similar based on your example.
Edit: returned Count as part of the return value as well, since it seemed to be important.
从 Erlang/OTP 21.2(2018 年 12 月发布)开始,您可以使用
计数器< /代码>模块
。该文档总结得很好:
例如,让我们创建一个计数器,将其递增 7,然后检查该值:
那么,如果多个进程需要访问,您在哪里存储计数器引用到它?您可以使用
persistent_term
来实现此目的,这也已添加到 Erlang 中/OTP 21.2:请注意,
persistent_term
只能用于很少或从不更改的值。您可能会在应用程序启动时创建计数器,将引用存储为持久项,然后在应用程序运行时访问它。As of Erlang/OTP 21.2 (released in December 2018), you can use the
counters
module. The documentation sums it up well: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.