Concurrency 代理是否应该只保存不可变的值

Concurrency 代理是否应该只保存不可变的值,concurrency,clojure,Concurrency,Clojure,在Clojure编程(OReilly)中,有一个示例,其中java.io.BufferedWriter和java.io.Printwriter都放在代理中(每个代理一个)。然后将它们写入代理操作内部。书中说在代理操作中执行io是安全的。据我所知,在代理操作中,所有的副作用操作都是正常的。这是因为只有在提交成功时,才会运行提交中的代理操作。其他代理操作中的代理操作仅在外部代理操作成功完成后运行。一般来说,保证连续应用代理操作 Clojure说:“代理的状态本身应该是不可变的……” 据我所知,原子和

在Clojure编程(OReilly)中,有一个示例,其中java.io.BufferedWriter和java.io.Printwriter都放在代理中(每个代理一个)。然后将它们写入代理操作内部。书中说在代理操作中执行io是安全的。据我所知,在代理操作中,所有的副作用操作都是正常的。这是因为只有在提交成功时,才会运行提交中的代理操作。其他代理操作中的代理操作仅在外部代理操作成功完成后运行。一般来说,保证连续应用代理操作

Clojure说:“代理的状态本身应该是不可变的……”

据我所知,原子和引用必须保持不变值的原因是clojure可以回滚并重试多次提交

我不明白的是:

1:如果Clojure确保代理操作只运行一次,为什么代理值必须是不可变的。 (例如,如果我在代理中持有一个java数组,并在代理操作中添加到该数组中,这应该没问题,因为该操作只运行一次。这与向BufferedWriter添加行非常相似)

2:java.io.BufferedWriter被认为是不可变的吗?我知道您可以有一个对它的稳定引用,但是如果代理操作正在对它执行io,它是否仍然应该被认为是不可变的


3:如果BufferedWriter被认为是不可变的,我如何确定其他类似的java类是否是不可变的?

我认为:

代理持有的值应该是“有效不变的”(从JCIP借用的术语),因为它们在概念上应该始终与自身相等

这意味着,如果我
.clone()
一个对象并比较两个副本,
original.equals(copy)
应该为true,无论我做什么(以及何时)

从这个意义上讲,面对易变性,
equals()
将被定义为一个字段对字段的比较,因此测试可能会失败,因此无法保证充满getter/setter的典型
Employee
类的实例与其自身相等

不过,BufferedWriter并不表示值——它的相等性是根据内存中完全相同的对象来定义的。所以它有一个“合理的”易变性-不像员工的-这使得它很容易包装在代理中

我相信你是对的,从STM的角度来看,代理价值的易变性不会造成太大的伤害。但这将打破Clojure的时间模型,在这个模型中,你“无法改变过去”,等等

决定Java类是否是不可变的:不深入实现是不可能的。不过你不必太在意这个

我将在Java land中对类型进行以下分类:

  • 表示值的可变对象-
    Employee
    ,等等。永远不要将它们包装在Clojure引用类型中

  • 表示值的不可变对象—它们的不可变性反映在文档或命名约定(“EmployeeBuilder”)中。可以安全地包装在任何Clojure引用中

  • 非托管集合类型-ArrayList等。除非出于互操作目的,否则应避免

  • 托管引用/集合类型-原子引用、阻塞队列。。。他们和Clojure玩得很好,但用Clojure的引用来包装他们是可疑的

  • “IO”类型-BufferedWriter、Swing之类的东西。。。你不在乎它们的易变性,因为它们根本不代表价值观——你只需要它们的副作用。在代理中保护它们以保证访问序列化可能是有意义的


代理值应该是不可变的,因为有人可以这样做:

 (def my-agent (agent (BufferedWriter.)))
 (.write @my-agent "Hello world")
这基本上是修改代理值(在本例中是writer),而不通过代理控制机制


是的,
BufferedWriter
是可变的,因为通过向其写入,可以更改其内部状态。它就像一个指针或引用,而不是一个
值。

虽然没有人使用BufferedWriter作为引用或集合类型,但对它们进行变异更像是一种副作用,而不是表示程序中的更改。BufferedWriter可以写入任何底层流,甚至可以是内存流,因此它可以是状态我想是的,严格地说:)我发现无论如何都非常重要:1)区分各种可变性,2)Clojure作为一种动态类型语言,将某些责任委托给程序员。不编写像
(.write@my agent“Hello world”)
(一般情况下)这样的代码就是其中之一。