Mar*_*ars 6 java clojure thread-safety clojure-java-interop
在单线程程序中使用:volatile-mutable限定符是否安全deftype?这是一个跟进这个问题,这一个和这一个.(这是一个Clojure问题,但我添加了"Java"标签,因为Java程序员也可能对它有洞察力.)
我发现在一个程序中我可以通过使用:volatile-mutable字段deftype而不是原子来获得显着的性能提升,但我很担心,因为文档字符串deftype说:
请注意,可变字段非常难以正确使用,并且只是为了便于在Clojure本身中构建更高级别的构造,例如Clojure的引用类型.它们仅供专家使用 - 如果:volatile-mutable或:unynchronized-mutable的语义和含义对您来说不是很明显,那么您就不应该使用它们.
事实上,语义和影响:volatile-mutable都不会马上对我明显.
然而,Emerick,Carper和Grand 的Clojure Programming第6章说:
这里的"Volatile"与Java中的volatile字段修饰符含义相同:读取和写入都是原子的,必须按程序顺序执行; 即,它们不能由JIT编译器或CPU重新排序.因此,挥发性物质并不令人惊讶,并且不会引起线程安全 - 但不协调,仍然完全对种族条件开放.
这似乎暗示只要访问单个volatile-mutable deftype字段都发生在一个线程中,就没有什么特别值得担心的了.(没有什么特别的,因为我还是要小心,我是如何处理的状态,如果我可能会使用懒惰序列.)因此,如果没有引入并行到我的Clojure程序,应该使用没有特殊的危险deftype用:volatile-mutable.
那是对的吗?我不明白有什么危险?
没错,这是安全的。您只需确保您的上下文确实是单线程的。有时要保证这一点并不容易。
在单线程上下文中使用易失性可变(或只是可变)字段时,不存在线程安全或原子性风险,因为只有一个线程,因此两个线程不可能向该字段写入新值同时,或者一个线程根据过时的值写入新值。
正如其他人在评论中指出的那样,您可能只想简单地使用一个:unsynchronized-mutable字段来避免 volatile 带来的成本。该成本来自以下事实:每次写入都必须提交到主内存而不是线程本地内存。有关此内容的更多信息,请参阅此答案。
同时,在单线程上下文中使用 volatile 不会带来任何好处,因为一个线程不可能写入一个不会被读取同一字段的其他线程“看到”的新值。这就是 volatile 的用途,但它在单线程上下文中无关紧要。
另请注意,clojure 1.7 引入的volatile!目的是提供一个“用于管理状态的易失性框”,作为atom的更快替代品,具有类似的界面,但没有比较和交换语义。使用它时的唯一区别是您调用vswap!andvreset!而不是swap!and reset!。^:volatile-mutable如果我需要 volatile,我会使用它而不是 deftype with 。
| 归档时间: |
|
| 查看次数: |
322 次 |
| 最近记录: |