C#懒惰<;T>&;竞相初始化?
(问了之后,我还有一个问题。)C#懒惰<;T>&;竞相初始化?,c#,.net,multithreading,.net-4.0,lazy-evaluation,C#,.net,Multithreading,.net 4.0,Lazy Evaluation,(问了之后,我还有一个问题。) Lazy的整个思想(AFAIK)是仅在需要时创建对象。 为什么?因为这是昂贵的创造 我最不希望的事情是昂贵的对象将被创建>1次 我不在乎是否许多线程最终会产生相同的引用。我只是不希望他们创建多个实例 所以Lazyinitializer通过syncLock处理这个问题: LazyInitializer.EnsureInitialized (ref _expensive, ref useless, ref _sync, () => new Expensive()
Lazy
的整个思想(AFAIK)是仅在需要时创建对象。
为什么?因为这是昂贵的创造
我最不希望的事情是昂贵的
对象将被创建>1次
我不在乎是否许多线程最终会产生相同的引用。我只是不希望他们创建多个实例
所以Lazyinitializer
通过syncLock
处理这个问题:
LazyInitializer.EnsureInitialized (ref _expensive, ref useless, ref _sync, () => new Expensive());
但是Lazy
如何处理呢?
我已在msdn中搜索,但找不到任何syncLock
重载
我遗漏了什么?听起来你想看看构造函数重载,它采用了LazyThreadSafetyMode
Lazy<T> lazy = new Lazy<T>(() => new T, LazyThreadSafetyMode.ExecutionAndPublication);
Lazy-Lazy=new-Lazy(()=>newt,LazyThreadSafetyMode.ExecutionAndPublication);
Lazy
基本上是一个用户友好的LazyInitializer
版本,单线程或多线程init的精确实现隐藏在该枚举后面。您是否在问Lazy在内部是如何工作的?Lazy保证只创建一个,如下所示:
默认情况下,惰性对象是线程安全的。也就是说,如果构造函数
不指定线程安全的类型,它的惰性对象
创建线程安全的。在多线程场景中,第一个线程
要访问线程安全惰性对象的Value属性,请初始化
它用于所有线程上的所有后续访问,并且所有线程共享
同样的数据。因此,初始化哪个线程并不重要
对象和种族条件都是良性的
如果您实际上是在问它内部是如何工作的,那么它似乎在使用某种类型的锁
:
object obj = Volatile.Read<object>(ref this.m_threadSafeObj);
bool flag = false;
try
{
if (obj != Lazy<T>.ALREADY_INVOKED_SENTINEL)
{
Monitor.Enter(obj, ref flag);
}
if (this.m_boxed == null)
{
boxed = this.CreateValue();
this.m_boxed = boxed;
Volatile.Write<object>(ref this.m_threadSafeObj, Lazy<T>.ALREADY_INVOKED_SENTINEL);
}
else
{
boxed = (this.m_boxed as Lazy<T>.Boxed);
if (boxed == null)
{
Lazy<T>.LazyInternalExceptionHolder lazyInternalExceptionHolder = this.m_boxed as Lazy<T>.LazyInternalExceptionHolder;
lazyInternalExceptionHolder.m_edi.Throw();
}
}
}
finally
{
if (flag)
{
Monitor.Exit(obj);
}
}
objectobj=Volatile.Read(参考this.m_threadSafeObj);
布尔标志=假;
尝试
{
if(obj!=懒惰。已调用\u哨兵)
{
监视器输入(obj,ref标志);
}
if(this.m_boxed==null)
{
boxed=this.CreateValue();
this.m_boxed=已装箱;
Volatile.Write(参考this.m_threadSafeObj,Lazy.ready_调用了_SENTINEL);
}
其他的
{
boxed=(this.m_被装箱为Lazy.boxed);
如果(已装箱==null)
{
Lazy.LazyInternalExceptionHolder LazyInternalExceptionHolder=此.m_装箱为Lazy.LazyInternalExceptionHolder;
lazyInternalExceptionHolder.m_edi.Throw();
}
}
}
最后
{
国际单项体育联合会(旗)
{
监控出口(obj);
}
}
注意监视器。输入和监视器。退出调用。wt*?像在LazyInitializer中创建的那样添加syncobj有那么难吗?Lazy
withExecutionAndPublication
相当于LazyInitializer
withsyncLock
。你只会得到一个实例。@Royi通常不是关于某件事是否“困难”(尽管这可能是一个因素),而是:它是否需要?它有用吗?我猜这两个中的一个失败了。Lazy-of-T中的监视器用法相当微妙。但是根据@bfree-Lazy自动执行…?默认的ctor指定ExecutionAndPublication
。Bfree是正确的,您可以只使用默认的ctor。当它使用Monitor时,它并不是以我称之为“简单”的方式这样做的。