我正在开发一个需要具有volatile语义的long类型的组件.
由于.NET中没有volatile,我创建了一个简单的包装器类型,它使用Volatile类处理读/写访问.
我不确定是否应该使用类或结构,所以我决定对它们进行测试,然后我遇到了一个非常奇怪的行为.
由于.NET中没有volatile,我创建了一个简单的包装器类型,它使用Volatile类处理读/写访问.
我不确定是否应该使用类或结构,所以我决定对它们进行测试,然后我遇到了一个非常奇怪的行为.
这是测试代码:
internal class Program { private class VolatileLongClass { private long value; public long Value { get { return Volatile.Read(ref value); } set { Volatile.Write(ref this.value,value); } } } private struct VolatileLongStruct { private long value; public long Value { get { return Volatile.Read(ref value); } set { Volatile.Write(ref this.value,value); } } } private static void Main() { const int iterations = 10; var totalTime = 0L; for (var i = 0; i < iterations; i++) { var watch = Stopwatch.StartNew(); var volatileLong = new VolatileLongClass(); //<-- change to VolatileLongStruct for (var j = 0L; j < 10 * 1000 * 1000; j++) volatileLong.Value = j; var msElapsed = watch.ElapsedMilliseconds; Console.Out.WriteLine("Ms Elapsed = {0}",msElapsed); totalTime += msElapsed; } Console.Out.WriteLine("Avg = {0:N2}",(double) totalTime / iterations); } }
我得到的VolatileLongStruct的输出:
Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Ms Elapsed = 109 Avg = 109.00
结构的上述输出是一致的.但是,VolatileLongClass的输出是:
Ms Elapsed = 17558 <-- *** Ms Elapsed = 105 Ms Elapsed = 105 Ms Elapsed = 105 Ms Elapsed = 105 Ms Elapsed = 105 Ms Elapsed = 17541 <-- *** Ms Elapsed = 105 Ms Elapsed = 105 Ms Elapsed = 105 Avg = 3,593.90
正如您所看到的,某些迭代存在很大的时间差异.花费异常时间的精确迭代略有不同,但至少有一次迭代存在一致的问题.
有人可以解释为什么一个易变的写入(有时)在类成员上(有时)长于结构成员吗?
顺便说一句,上面的结果是使用.Net 4.5和Release版本生成的
解决方法
时差很可能是var volatileLong = new VolatileLongClass()的结果;循环内;该语句使编译器 – 一次 – 分配空间来保存VolatileLongClass引用,然后在每次通过循环时创建一个新对象并将引用存储到该位置.相比之下,语句var volatileLong = new VolatileLongStruct();导致编译器 – 一次 – 分配空间来保存VolatileLongStruct实例,然后在每次通过循环时通过将所有数据归零(使用正常而非易失性写入)来改变预先存在的实例.
请注意,如果代码将要求结构字段具有特定的多线程语义,则这些字段通常应该公开,并且结构应该被视为与管道磁带粘在一起的一组变量[例如public struct IntPair {public int V1,V2;} IntPair myPair;应该被视为创建两个单独的变量myPair.V1和myPair.V2].事实上,结构是由管道磁带粘在一起的变量的组合,并且由于大小不是1,2或4字节的结构所呈现的任何其他抽象必然是“泄漏的”,尤其是关于多线程行为,一个结构体更好地呈现它本身就是它,而不是假装它不是它的东西.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。