请分享您的看法,参加 2024 Clojure 状态调查!

欢迎!有关如何操作的更多信息,请参阅 关于 页面。

+2
记录和类型
重新分类

作为一个非常看重原子以及比较和设置作为并发原语的人,如果能在不增加开销(更多的对象占用更多内存和更多的指针追踪)的情况下在 deftype 的可变字段上进行比较和设置,将会很方便。

Java虚拟机有几种机制可以直接在字段上进行CAS操作(AtomicReferenceFieldUpdater、VarHandles等)。似乎deftype可以在请求时提供这样的功能。

目前可以使用AtomicReferenceFieldUpdater来与deftype配合使用,但因为私有volatile字段和缺失静态初始化器,所以略显复杂。

1 个回答

0

这似乎是一个有趣的请求,但它更像是一个解决方案而不是一个问题。您能否从那个角度来看重述它?

很抱歉,我并不明白你在问什么。

我想这是你第二次或第三次提出类似的反馈(之前在#clojure-dev中),我已经重新编写过一次(我以为)已经包含了那个反馈。感谢你花时间,但看起来我很明显还是不明白。
也就是说,“我正尝试做X,但做不到”。X是什么?需要这样做的情况是什么?
这是一个好笑的错误喜剧,我之前基本误解了相反的情况,并删除了所有关于我的特定问题引用。

我编写了一种定制的引用类型,不是真正的Clojure引用类型,但类似的事物。一个对盒子内容的控制变异进行包装的盒子。A最终会有一些类似atom或ref的样子。

我的类型是引用类型,有一个可变字段,它指向引用本身指向的内容,还有其他字段以方便其他操作。我想使用比较和设置来变异这个可变字段。

在"vanilla" Clojure中编写,唯一的方式来此是通过在deftype字段持有值周围使用atom或AtomicReference包装器。这可以工作,但增加了1或2个指针追踪级别。我想去掉那些额外的指针。

Java提供了至少两种直接在可变字段上执行比较和设置的设施(它们可能需要字段是volatile的,我忘记了)。这两种机制都通过创建一种字段访问器对象来实现。类的一个典型模式似乎是创建字段访问器对象在静态初始化器中,然后在执行cas类型操作时,根据实例的字段使用它。

标准的模式与当前的deftype不兼容,因为虽然你可以将deftype字段设置为可变的,但这也会使其成为私有的,从而使得构建字段访问器对象变得困难。由于字段是私有的,因此你无法从外部构建它,并且deftype没有提供进行静态初始化的方法。解决这个问题有几种方法,基本上是给deftype添加一个方法,这个方法除了创建和返回字段访问器对象外,什么都不做。然后在某些顶级静态环境中构建一个dummy类的实例并调用该方法。因此,这种方法是可行的,但令人相当头疼。

起初我尝试创建dummy的deftype实例,但最终只是编写了一个极为简化的deftype版本,通过生成一个类,该类具有字段和一个静态初始化器,用于设置特定字段的AtomicReferenceFieldUpdater。这也可行,但这需要一些使用asm库的经验,并且需要注意使其与AOT编译(我想我已经做对了,但并不确定)良好兼容。

比较和设置是一个很棒的功能,如果能提供一个在不围绕我们要比较和设置的内容添加额外对象包装的情况下在deftype字段上执行它的方式就更好了。在Java/JVM中存在实现这一功能的方法,但在Clojure中利用它们相当痛苦。
by
我认为亚历克斯的要求仍然没有得到满足。即使是通过使用类似原子引用的引用和比较和设置,即使可变状态是解决问题的方法,但是解决的问题是什么?使用可变状态和CAS解决了什么问题?

如果我们能回到原始问题,那么可能会发生以下两种情况之一……要么1)我们发现使用Clojure中的现有结构解决这个问题的其他好方法,要么2)我们面临一个具有挑战性的未解决问题,这可能导致语言本身、库或新库的增加。
by
我来到这里是因为我在想,使用具有可变状态的deftype可能是我所面临问题的解决方案。我的UI基于Clojure代码,我需要实现/扩展一个TableModel实现并传递给我的JTable实例。不知何故,我需要更新TableModel的内容...我猜想我可以完全重建它,并每次都向JTable提供一个新TableModel,但这对Swing来说似乎不是很高效。我也可以使用gen-class - 如果这是最好的方法,那就没问题。我想要显示的数据在我的应用程序状态中,我的应用程序状态在一个atom中。当数据发生变化时,我想将更改发送到应用程序状态atom的swap!,并将这些更改传播回TableModel,然后使用JTable显示它们。所以问题/困难是怎么样将TableModel连接到应用程序状态。
将这些内容写出来,我的解决方案似乎很清楚...直接从TableModel引用应用程序状态,并在应用程序状态更改时触发table结构/行等的更改。然而,还有一个我没有提到的层面。我实际上正在使用FRP(函数式响应式编程)进行UI。因此,视图是应用程序状态的一个函数。视图函数是一个纯函数,但由于Swing中JTable的编码方式,它必须包含实际数据的引用。所以,要么我在每次视图渲染时创建一个新的TableModel,要么在TableModel中使用某种自定义或现有类存储状态,违规此处的FRP模型,或者是我还没有想到的某种方法。
...