gpt4 book ai didi

c# - 深度不可变类型的惰性初始化是否需要锁?

转载 作者:可可西里 更新时间:2023-11-01 09:03:47 25 4
gpt4 key购买 nike

如果我有一个深度不可变类型(所有成员都是只读的,如果它们是引用类型成员,那么它们也引用深度不可变的对象)。

我想在类型上实现一个惰性初始化属性,如下所示:

private ReadOnlyCollection<SomeImmutableType> m_PropName = null;
public ReadOnlyCollection<SomeImmutableType> PropName
{
get
{
if(null == m_PropName)
{
ReadOnlyCollection<SomeImmutableType> temp = /* do lazy init */;
m_PropName = temp;
}
return m_PropName;
}
}

据我所知:

m_PropName = temp; 

...是线程安全的。我不太担心两个线程同时竞相初始化,因为这种情况很少见,从逻辑角度来看,两个结果都是相同的,如果我没有,我宁愿不使用锁到。

这行得通吗?有什么优点和缺点?

编辑:感谢您的回答。我可能会继续使用锁。然而,令我惊讶的是,没有人提出编译器可能意识到临时变量是不必要的,而只是直接分配给 m_PropName。如果是这种情况,那么读取线程可能会读取一个尚未完成构建的对象。编译器会阻止这种情况吗?

(答案似乎表明运行时不允许这种情况发生。)

编辑:所以我决定采用受 this article by Joe Duffy 启发的 Interlocked CompareExchange 方法。 .

基本上:

private ReadOnlyCollection<SomeImmutableType> m_PropName = null;
public ReadOnlyCollection<SomeImmutableType> PropName
{
get
{
if(null == m_PropName)
{
ReadOnlyCollection<SomeImmutableType> temp = /* do lazy init */;
System.Threading.Interlocked(ref m_PropName, temp, null);
}
return m_PropName;
}
}

这应该确保所有在此对象实例上调用此方法的线程都将获得对同一对象的引用,因此 == 运算符将起作用。可能会浪费工作,这很好 - 它只是使它成为一个乐观的算法。

如以下一些评论所述,这取决于 .NET 2.0 内存模型的工作。否则,m_PropName 应声明为可变的。

最佳答案

那行得通。在 C# 中写入引用保证是原子的,如 spec 的第 5.5 节所述。 .这仍然可能不是一个好的方法,因为您的代码将更容易调试和阅读,以换取对性能可能很小的影响。

Jon Skeet 有很棒的 page关于在 C# 中实现单例。

关于此类小型优化的一般建议是不要执行它们,除非分析器告诉您此代码是热点。此外,您应该警惕编写大多数程序员在不检查规范的情况下无法完全理解的代码。

编辑:如评论中所述,即使您说您不介意创建对象的 2 个版本,但这种情况是如此违反直觉,因此永远不应使用这种方法。

关于c# - 深度不可变类型的惰性初始化是否需要锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/652195/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com