【发布时间】:2012-02-26 06:56:12
【问题描述】:
我是 Clojure 的新手,你们能给我解释一下现实世界的场景吗?我的意思是,在哪里使用 Ref、Var、Agent、Atom。我读了书,但是,仍然无法理解现实世界的例子。
【问题讨论】:
我是 Clojure 的新手,你们能给我解释一下现实世界的场景吗?我的意思是,在哪里使用 Ref、Var、Agent、Atom。我读了书,但是,仍然无法理解现实世界的例子。
【问题讨论】:
我强烈推荐“Clojure 的乐趣”或“Clojure 编程”以获得这个问题的真正答案,我可以复制每个动机的简短片段:
首先观看this video on the notion of Identity 和/或studying here。
协调访问,经典示例是将资金从一个银行帐户转移到另一个银行帐户,它需要完全转移或根本不转移。
Uncoordinated 访问仅在一个身份需要更新时使用,这是一种非常常见的情况。
同步 访问用于当调用预计要等到所有身份都解决后再继续时。
异步访问是“一劳永逸”,让身份在它自己的时间达到它的新状态。
【讨论】:
state-a,但在这样做时参考state-b,我仍然需要ref对吗?所以它不是改变多个事物,而是在改变任何事物的同时引用多个事物?
ensure 函数:clojure.github.io/clojure/clojure.core-api.html#clojure.core/… 使其更明确且更高效。
Refs 用于需要在线程之间同步的状态。如果您需要跟踪一堆不同的事物,并且有时需要执行一次写入多个事物的操作,请使用 refs。任何时候你有多个不同的状态,使用 refs 不是一个坏主意。
原子用于需要在线程之间同步的独立状态。如果你永远不需要同时改变 atom 和其他任何东西的状态,使用 at atom 是安全的(特别是,如果整个程序中只有一个状态,你可以把它放在一个 atom 中) .举一个不平凡的例子,如果你试图缓存一个函数的返回值(即记忆它),使用原子可能是安全的 - 状态对函数之外的所有东西都是不可见的,所以你不需要担心关于函数内部的状态变化搞砸了。
代理的主要观点是它们在不同的线程中运行。您可以获取代理的值并告诉它对其值应用一个函数,但您不知道该函数何时运行或该函数将应用于什么值。
变量适用于需要在每个线程基础上存储内容的情况。如果您有一个多线程程序并且每个线程都需要自己的私有状态,则将该状态放入 var 中。
就现实世界的示例而言,如果您提供一个您正在尝试做什么的示例,我们可以告诉您使用什么。
【讨论】:
当我第一次读到这些类型时,我也很难理解我可以或应该在哪里使用每种类型,所以这是我简单的英语回答:
当数据不变时使用 var。每当您使用def 或大多数以def 开头的函数(如defn)时,都会发生这种情况。
当您有单个项目发生变化时使用原子。一个示例可能是您想要添加项目的计数器或向量。
当您有两个或多个必须同时更改的内容时,请使用 ref。如果您熟悉,请考虑“数据库事务”。典型的例子是将资金从一个账户转移到另一个账户。每个帐户都可以存储在一个 ref 中,以便可以进行更改以使其看起来是原子的。
当您想要更改某些内容但不在乎何时更改时,请使用代理。这可能是一个很长的计算或将某些内容写入文件或套接字。请注意,对于后者,您应该使用send-off。
注意:我很欣赏这些内容中的每一个都有很多内容,但希望这可以为您提供一个起点。
【讨论】:
我写了一篇文章,总结了它们之间的区别,并帮助选择何时使用哪一个。
Share state - when use vars, atoms, agents and refs?
我希望它能帮助人们寻找该主题的答案。
@tunaci 建议后文章中的一些捷径:
变量
变量对于每个线程都是全局的。
创建后不要更改变量。这在技术上是可行的,但它是 出于多种原因,这是个坏主意。
原子
为每个线程共享对可变状态的访问。发生变化 同步。当其他线程在运行期间改变状态时重试。
不要使用非幂等函数和长时间的函数 执行
代理
为每个线程共享对可变状态的访问。发生变化 异步。
参考文献
Refs 的工作方式类似于数据库事务。写和读是 在dosync中保护。您可以在事务中安全地对许多 ref 进行操作。
请查看网站上的图片,因为总有一些更新是可能的。
在没有复制和过去的文章的情况下给出完整的答案是一个复杂而漫长的话题,所以请原谅我将您重定向到网站:)
【讨论】:
atoms、refs 和 agent - 这里有一些说明 http://blog.jayfields.com/2011/04/clojure-state-management.html
【讨论】: