如何维护Erlang的状态? [英] How to maintain state in Erlang?

查看:68
本文介绍了如何维护Erlang的状态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我已阅读的许多博客中,我已经看到人们使用 dict,ordict,record 来保持状态。我觉得这是非常重要的概念。

I have seen people use dict,ordict,record for maintaining state in many blogs that i have read.I find it as very vital concept.

通常,我了解维持状态,递归的含义,但是当涉及到erlang时。.我对其处理方式含糊不清。

Generally I understand the meaning of mantaining state,recursions but when it comes to erlang..I am a little vague about how it is handled.

有帮助吗?

推荐答案

状态是数据的当前排列方式。有时由于以下两个原因很难记住这一点:

State is the present arrangement of data. It is sometimes hard to remember this for two reasons:


  • 状态表示程序中的数据以及程序的当前执行点,而模式。

  • 我们将其不必要地构建为一些神奇的东西。

考虑一下:

进程的状态是什么?正在询问变量的现值。

"What is the process's state?" is asking about the present value of variables.

进程处于什么状态?通常是指执行的模式,选项,标志或当前位置。

"What state is the process in?" usually refers to the mode, options, flags or present location of execution.

如果您是图灵机,那么这些问题是相同的;我们已经分离了想法,以便为我们提供方便的抽象基础(就像编程中的其他所有内容一样)。

If you are a Turing machine then these are the same question; we have separated the ideas to give us handy abstractions to build on (like everything else in programming).

让我们暂时考虑一下状态变量...

在许多较旧的语言中,您可以根据自己的喜好更改状态变量,无论状态修改是否适当,因为您可以直接对其进行管理。在更现代的语言中,通过对变量施加类型声明,作用域规则和公共/私有上下文,这受到了更多限制。这实际上是一条竞赛规则,每种语言都可以找到更多方法来限制分配的时间。如果说调度是并发编程中挫败的王子,那么分配就是魔鬼本身。因此,为管理他而建造了各种各样的笼子。

In many older languages you can alter state variables from whatever context you like, whether the modification of state is appropriate or not, because you manage this directly. In more modern languages this is a bit more restricted by imposing type declarations, scoping rules and public/private context to variables. This is really a rules arms-race, each language finding more ways to limit when assignment is permitted. If scheduling is the Prince of Frustration in concurrent programming, assignment is the Devil Himself. Hence the various cages built to manage him.

Erlang通过设置以下基本规则来限制以不同的方式允许分配的情况:每个条目每次只能分配一次。函数和函数本身是过程范围的唯一定义,并且 all 状态完全由执行过程封装。 (想想关于范围的声明,以了解为什么很多人认为Erlang宏是一件坏事。)

Erlang restricts the situations that assignment is permitted in a different way by setting the basic rule that assignment is only once per entry to a function, and functions are themselves the sole definition of procedural scope, and that all state is purely encapsulated by the executing process. (Think about the statement on scope to understand why many people feel that Erlang macros are a bad thing.)

这些赋值规则(使用状态变量)鼓励您将状态看作是谨慎的时间片。无论函数是否递归,函数的每个条目均以干净的开头开头。这与大多数其他语言从任何地方到任何地方进行的正在进行的就地修改的混乱情况截然不同。在Erlang中,您永远不会问现在X 的值是什么?因为它只能是在当前函数的当前运行上下文中最初被分配为的内容。这极大地限制了功能和过程中状态变化的混乱。

These rules on assignment (use of state variables) encourage you to think of state as discreet slices of time. Every entry to a function starts with a clean slate, whether the function is recursive or not. This is a fundamentally different situation than the ongoing chaos of in-place modifications made from anywhere to anywhere in most other languages. In Erlang you never ask "what is the value of X right now?" because it can only ever be what it was initially assigned to be in the context of the current run of the current function. This significantly limits the chaos of state changes within functions and processes.

这些状态变量的详细信息以及如何分配状态变量是Erlang附带的。您已经了解列表,元组,ETS,DETS,mnesia,数据库连接等。了解Erlang风格的核心思想是赋值的管理方式,而不是此或该特定数据类型的附带细节。

The details of those state variables and how they are assigned is incidental to Erlang. You already know about lists, tuples, ETS, DETS, mnesia, db connections, etc. Whatever. The core idea to understand about Erlang's style is how assignment is managed, not the incidental details of this or that particular data type.

模式和执行状态如何?

如果我们这样写:

has_cheeseburger(BurgerName)
  receive
    {From, ask, burger_name} ->
        From ! {ok, BurgerName},
        has_cheeseburger(BurgerName);
    {From, new_burger, _SomeBurger} ->
        From ! {error, already_have_a_burger},
        has_cheeseburger(BurgerName);
    {From, eat_burger} ->
        From ! {ok, {ate, BurgerName}},
        lacks_cheeseburger()
  end.

lacks_cheeseburger()
  receive
    {From, ask, burger_name} ->
        From ! {error, no_burger},
        lacks_cheeseburger();
    {From, new_burger, BurgerName} ->
        From ! {ok, thanks},
        has_cheeseburger(BurgerName);
    {From, eat_burger} ->
        From ! {error, no_burger},
        lacks_cheeseburger()
  end.

我们在看什么?一个循环。从概念上讲,它只是一个循环。通常,程序员会选择只在代码中编写一个循环,并在循环中添加诸如 IsHoldingBurger 之类的参数,并在接收到中的每条消息后进行检查。 子句确定要采取的操作。

What are we looking at? A loop. Conceptually its just one loop. Quite often a programmer would choose to write just one loop in code and add an argument like IsHoldingBurger to the loop and check it after each message in the receive clause to determine what action to take.

不过,以上两种操作模式的思想都更加明确(将其烘焙到结构中,而不是任意的程序测试),并且不太冗长。我们通过基本编写相同的循环两次来分离执行上下文,对于可能遇到的每个条件(汉堡或缺少汉堡),都编写两次。这是Erlang处理称为有限状态机的概念及其确实有用的核心。 OTP在gen_fsm模块中包括一个围绕此想法构建的工具。您可以像上面一样手动编写自己的FSM,也可以使用gen_fsm -无论哪种方式,当您确定自己遇到这种情况时,以这种方式编写代码会使推理变得容易得多。 (对于除最琐碎的FSM之外的任何事物,您都会非常喜欢gen_fsm。)

Above, though, the idea of two operating modes is both more explicit (its baked into the structure, not arbitrary procedural tests) and less verbose. We have separated the context of execution by writing basically the same loop twice, once for each condition we might be in, either having a burger or lacking one. This is at the heart of how Erlang deals with a concept called "finite state machines" and its really useful. OTP includes a tool build around this idea in the gen_fsm module. You can write your own FSMs by hand as I did above or use gen_fsm -- either way, when you identify you have a situation like this writing code in this style makes reasoning much easier. (For anything but the most trivial FSM you will really appreciate gen_fsm.)

结论

在Erlang中处理状态就是这样。单一分配的基本规则和每个进程中绝对数据封装的基本规则使无限制分配的混乱变得毫无用处(顺便说一句,这意味着您不应该编写巨大的进程)。有限的一组工作模式的最有用的概念是由OTP模块gen_fsm提取的,或者可以很容易地用手工编写。

That's it for state handling in Erlang. The chaos of untamed assignment is rendered impotent by the basic rules of single-assignment and absolute data encapsulation within each process (this implies that you shouldn't write gigantic processes, by the way). The supremely useful concept of a limited set of operating modes is abstracted by the OTP module gen_fsm or can be rather easily written by hand.

由于Erlang的工作如此出色,限制了单个进程中状态的混乱,使进程间并发调度的噩梦完全不可见,这只剩下一个复杂的怪物:松散耦合的参与者之间的交互混乱。在Erlanger的心中,这就是复杂性所在。通常,困难的东西应该出现在消息的无人之地,而不是功能或过程本身中。您的函数应该很小,对程序检查的需求相对很少(与C或Python相比),对模式标志和开关的需求几乎不存在。

Since Erlang does such a good job limiting the chaos of state within a single process and makes the nightmare of concurrent scheduling among processes entirely invisible, that only leaves one complexity monster: the chaos of interactions among loosely coupled actors. In the mind of an Erlanger this is where the complexity belongs. The hard stuff should generally wind up manifesting there, in the no-man's-land of messages, not within functions or processes themselves. Your functions should be tiny, your needs for procedural checking relatively rare (compared to C or Python), your need for mode flags and switches almost nonexistant.

编辑

以超级有限的方式重申Pascal的回答:

To reiterate Pascal's answer, in a super limited way:

loop(State)
  receive
    {async, Message} ->
        NewState = do_something_with(Message),
        loop(NewState);
    {sync, From, Message} ->
        NewState = do_something_with(Message),
        Response = process_some_response_on(NewState),
        From ! {ok, Response},
        loop(NewState);
    shutdown ->
        exit(shutdown);
    Any ->
        io:format("~p: Received: ~tp~n", [self(), Any]),
        loop(State)
  end.

重新阅读tkowal对最小版本的回复。重新阅读Pascal,以扩展相同的想法,以包括服务消息。重新阅读以上内容,以了解状态处理中 same 模式的样式略有不同,并增加了发出意外消息的可能性。最后,重新阅读我在上面编写的两个状态的循环,您实际上会看到它实际上是对该相同想法的又一次扩展。

Re-read tkowal's response for the most minimal version of this. Re-read Pascal's for an expansion of the same idea to include servicing messages. Re-read the above for a slightly different style of the same pattern of state handling with the addition of ouputting unexpected messages. Finally, re-read the two-state loop I wrote above and you'll see its actually just another expansion on this same idea.

记住,您不能-在函数的同一迭代中分配变量 ,但下一次调用可以具有不同的状态。这是Erlang中状态处理的程度。

Remember, you can't re-assign a variable within the same iteration of a function but the next call can have different state. That is the extent of state handling in Erlang.

这些都是同一事物的变体。我认为您期望会有更多,更广泛的机制或其他功能。那没有。限制分配可以消除您可能习惯于用其他语言查看的所有内容。在Python中,您执行 somelist.append(NewElement),现在您已更改的列表已更改。在Erlang中,您执行 NewList = list:append(NewElement,SomeList),并且SomeList与以前完全相同,并且返回了一个新列表,其中包括新元素。这是否实际上涉及在后台复制不是您的问题。您处理这些详细信息,所以不要考虑它们。这就是Erlang的设计方式,只剩下一次分配并进行新的函数调用,以输入新的时间片,再次将板岩擦拭干净。

These are all variations on the same thing. I think you're expecting there to be something more, a more expansive mechanism or something. There is not. Restricting assignment eliminates all the stuff you're probably used to seeing in other languages. In Python you do somelist.append(NewElement) and the list you had now has changed. In Erlang you do NewList = lists:append(NewElement, SomeList) and SomeList is sill exactly the same as it used to be, and a new list has been returned that includes the new element. Whether this actually involves copying in the background is not your problem. You don't handle those details, so don't think about them. This is how Erlang is designed, and that leaves single assignment and making fresh function calls to enter a fresh slice of time where the slate has been wiped clean again.

这篇关于如何维护Erlang的状态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆