Ref,Var,Agent,Atom之间的Clojure差异,以及示例

时间:2012-02-03 16:55:15

标签: clojure var agent

我是Clojure的新手,你能不能给我解释现实场景。我的意思是,在哪里使用Ref,Var,Agent,Atom。我读过书,但是,仍然无法理解现实世界的例子。

5 个答案:

答案 0 :(得分:157)

我强烈推荐“Clojure的喜悦”或“编程Clojure”来回答这个问题的真实答案,我可以重现一下每个动机的简短内容:

首先观看this video on the notion of Identity和/或studying here

  • 参考资料用于协调同步访问“多个身份”。
  • 原子用于不协调的同步访问单个身份。
  • 代理用于未协调的异步访问单个身份。
  • Vars用于具有共享默认值的线程本地隔离标识
当两个身份需要一起更改时,会使用

协调访问权限,典型的例子是将资金从一个银行帐户转移到另一个银行帐户,它需要完全移动或根本不移动。

当只有一个Identity需要更新时,使用

不协调访问,这是一种非常常见的情况。

同步访问是在预期呼叫等到所有身份都已确定之后才使用的。

异步访问是“一劳永逸”,让身份在其自己的时间内达到新的状态。

答案 1 :(得分:38)

Refs用于需要在线程之间同步的状态。如果你需要跟踪一堆不同的东西,你有时需要做一些写入多个事情的操作,使用refs。每当你有多个不同的状态时,使用refs并不是一个坏主意。

Atoms用于需要在线程之间同步的独立状态。如果你永远不需要同时改变原子和其他任何东西的状态,那么使用at atom是安全的(特别是,如果整个程序中只有一个状态,你可以把它放在一个原子中) 。作为一个非常重要的例子,如果你试图缓存一个函数的返回值(即memoize它),使用一个原子可能是安全的 - 状态对函数外的所有东西都是不可见的,所以你不必担心关于功能内部的状态变化搞乱任何事情。

代理主要的一点是它们在不同的线程中运行。您可以获取代理的值并告诉它将函数应用于其值,但您不知道该函数何时运行或该函数将应用于什么值。

Vars适用于需要在每个线程上存储内容的情况。如果您有一个多线程程序并且每个线程都需要自己的私有状态,请将该状态放在var。

就真实世界的例子而言,如果你提供一个你想要做的事情的例子,我们可以告诉你要使用什么。

答案 2 :(得分:29)

当我第一次阅读这些类型时,我也很难理解我能够或应该使用每一种类型,所以这里是我的简单英语答案:

当数据不会改变时使用var。只要您使用def或大多数以def开头的函数(例如defn),就会发生这种情况。

当您有一个更改的项目时使用原子。一个示例可能是您要添加项目的计数器或矢量。

如果您有两件或多件必须同时更改的东西,请使用参考号。如果您熟悉,请考虑“数据库事务”。这种规范的例子是将钱从一个账户转移到另一个账户。每个帐户都可以存储在ref中,以便可以使更改显示为原子。

当您想要更改某些内容时使用代理但您何时不关心。这可能是一个很长的计算或写入文件或套接字。请注意,对于后者,您应该使用send-off

注意:我很欣赏其中每一项都有很多,但希望这会给你一个起点。

答案 3 :(得分:21)

我写了文章,总结了它们之间的区别,并帮助选择何时使用哪一个。

Share state - when use vars, atoms, agents and refs?

我希望它能帮助人们在该主题中寻找答案。

@tunaci建议后文章的一些捷径:

<强>瓦尔

  

每个线程的Vars都是全局的。

     

创建后不要更改变量。这在技术上是可行的,但确实如此   坏主意有很多原因。

<强>原子

  

为每个线程共享对可变状态的访问权限。发生变化   同步。其他线程在运行期间更改状态时重试。

     

长时间不要使用非幂等函数和函数   执行

<强>剂

  

为每个线程共享对可变状态的访问权限。发生变化   异步。

<强>参考文献

  

Refs与数据库事务类似。写和读   在dosync中保护。您可以在交易中操作许多安全的参考。

使用哪一个流程图: flowchart

请查看网站上的图片,因为总有一些更新。

在没有副本的情况下提供完整答案是一个复杂而漫长的话题。过去的文章,请原谅我,我将你重定向到网站:)

答案 4 :(得分:4)

原子,refs和agent - 这里有一些照明 http://blog.jayfields.com/2011/04/clojure-state-management.html