在最近的Clojure 1.7版本中有一个补充:volatile!
volatile 已经在许多语言中使用,包括java,但Clojure中的语义是什么?
它有什么作用?什么时候有用?
Clo*_*tly 61
新的volatile与真正的"变量"(因为它来自许多其他编程语言)一样接近clojure.
从宣布:
有一组功能新的(
volatile!,vswap!,vreset!,volatile?)创建和使用挥发性的"盒子"的状态传感器,以保持状态.挥发物比原子快,但放弃了原子性保证,所以只能用于螺纹隔离.
例如,您可以像使用C中的变量一样设置/获取和更新它们.唯一的添加(因此名称)是实际java对象的volatile关键字.
这是为了防止JVM进行优化,并确保每次访问JVM时都会读取内存位置.从JIRA门票:
Clojure需要更快的Atom变体来管理传感器内部的状态.也就是说,Atoms可以完成这项工作,但它们为传感器提供了一些过多的功能.特别是Atoms的比较和交换语义增加了太多的开销.因此,确定简单的volatile ref类型将确保其值的基本传播到其他线程并从任何其他线程读取最新的写入.虽然更新受竞争条件的限制,但访问权限由JVM保证控制.
解决方案概述:在Java中创建一个类似于clojure.lang.Box的具体类型,但volatile内部支持IDeref,但不支持监视等.
这意味着,volatile!仍然可以通过多个线程访问(这对于传感器来说是必需的),但它不允许同时由这些线程更改,因为它不会给您原子更新.
volatile在java答案中很好地解释了什么做的语义:
线程安全有两个方面:(1)执行控制,(2)内存可见性.第一个与控制何时执行代码(包括执行指令的顺序)以及它是否可以并发执行有关,第二个与内存中对已完成内容的影响何时对其他线程可见有关.因为每个CPU在它和主内存之间有几级缓存,所以在不同CPU或内核上运行的线程在任何给定时刻都可以看到"内存"不同,因为允许线程获取并处理主内存的私有副本.
现在让我们看看为什么不使用var-set或transients:
没有可变的本地人,人们被迫使用recur,一个功能性的循环结构.虽然这一开始可能看起来很奇怪,但它与带有变异的循环一样简洁,并且得到的模式可以在Clojure的其他地方重复使用,即重复,减少,改变,通勤等都是(逻辑上)非常相似的.[...]无论如何,Vars可在适当时使用.
,从而创造with-local-vars,var-set等等.这些问题是,他们是真正的 增值经销商和的文档字符串var-set告诉你:
var必须是线程局部绑定的.
当然,这不是core.async的一个选项,它可能在不同的线程上执行.他们也慢得多,因为他们做了所有这些检查.
瞬态是类似的,因为它们不允许并发访问和优化变异数据结构.问题是瞬态仅适用于实现的集合IEditableCollection.也就是说,它们只是为了避免集合数据结构的昂贵中间表示.还要记住,瞬态不会到位,您仍然需要一些内存位置来存储实际的瞬态.挥发物通常用于简单地保持旗帜或最后一个元素的价值(partition-by例如参见)
Volatile只不过是java的volatile的包装,因此具有完全相同的语义.不要分享它们.只使用它们非常小心.
| 归档时间: |
|
| 查看次数: |
4365 次 |
| 最近记录: |