C# 懒惰的缺点<;T>;?
我最近开始在整个应用程序中使用,我想知道在使用C# 懒惰的缺点<;T>;?,c#,mef,C#,Mef,我最近开始在整个应用程序中使用,我想知道在使用Lazy时是否有任何明显的负面因素需要考虑 我正试图尽可能多地利用惰性,主要是为了帮助减少已加载但不活跃的插件的内存占用。与任何事情一样,惰性可以用于善或恶,因此有一个缺点:如果使用不当,可能会导致混乱和挫折。然而,惰性初始化模式已经存在多年了,现在.NETBCL已经有了一个实现,开发人员不再需要重新发明轮子。更重要的是,.我将对我的评论进行一些扩展,内容如下: 我刚开始使用Lazy,发现它通常是指示性的 设计不好;或者程序员的懒惰。还有一个 缺点是
Lazy
时是否有任何明显的负面因素需要考虑
我正试图尽可能多地利用
惰性
,主要是为了帮助减少已加载但不活跃的插件的内存占用。与任何事情一样,惰性
可以用于善或恶,因此有一个缺点:如果使用不当,可能会导致混乱和挫折。然而,惰性初始化模式已经存在多年了,现在.NETBCL已经有了一个实现,开发人员不再需要重新发明轮子。更重要的是,.我将对我的评论进行一些扩展,内容如下:
我刚开始使用Lazy,发现它通常是指示性的
设计不好;或者程序员的懒惰。还有一个
缺点是,你必须更加警惕的范围了
变量,并创建适当的闭包
例如,我使用了Lazy
来创建用户可以在我的(无会话)MVC应用程序中看到的页面。这是一个向导,因此用户可能希望转到随机的上一步。进行握手时,将装箱一组惰性
对象,如果用户指定为步骤,则会计算准确的页面。我发现它提供了良好的性能,但有一些方面我不喜欢,例如我的许多foreach
结构现在看起来如下:
foreach(var something in somethings){
var somethingClosure = something;
list.Add(new Lazy<Page>(() => new Page(somethingClosure));
}
foreach(在something中变量something){
var somethingClosure=某物;
添加(newlazy(()=>newpage(somethingClosure));
}
也就是说,您必须非常主动地处理闭包问题。否则,我认为存储lambda并在需要时对其进行评估不会对性能造成太大影响
另一方面,这可能表明程序员是一个懒惰的
,从某种意义上说,您不希望现在就仔细思考您的程序,而是在需要时让适当的逻辑进行评估,就像我的例子一样-我不需要构建该数组,而只需要找出特定请求的页面将是什么是的,但我选择了懒惰,采取了一种全方位的方法
编辑
我突然想到,
Lazy
在处理并发时也有一些特殊之处。例如,对于某些场景,有一个ThreadLocal
,对于特定的多线程场景,有几个标志配置。您可以阅读更多内容。您对“在我的应用程序中”的确切含义是什么
我认为只有当您不确定是否使用该值时才应该使用它,这可能只适用于需要很长时间计算的可选参数。这可能包括复杂的计算、文件处理、Web服务、数据库访问等
另一方面,为什么在这里使用Lazy
?在大多数情况下,您可以简单地调用一个方法,而不是Lazy.Value
,而且这没有任何区别。但是对于程序员来说,没有Lazy
,在这种情况下会发生什么更简单、更明显
一个明显的好处可能是已经实现了对值的缓存,但我不认为这是一个很大的优势。这不是一个很消极的方面,但对懒惰的人来说是一个难题:) 惰性初始值设定项类似于静态初始值设定项。他们跑了一次。如果引发异常,则会缓存该异常,对.Value的后续调用将引发相同的异常。这是经过设计的,并在文件中提到…: valueFactory引发的异常将被缓存 因此,下面的代码永远不会返回值:
bool firstTime = true;
Lazy<int> lazyInt = new Lazy<int>(() =>
{
if (firstTime)
{
firstTime = false;
throw new Exception("Always throws exception the very first time.");
}
return 21;
});
int? val = null;
while (val == null)
{
try
{
val = lazyInt.Value;
}
catch
{
}
}
bool firstTime=true;
懒惰懒汉=新懒汉(()=>
{
如果(第一次)
{
第一次=错误;
抛出新异常(“总是在第一次抛出异常。”);
}
返回21;
});
智力?val=null;
while(val==null)
{
尝试
{
val=懒散值;
}
抓住
{
}
}
在我看来,你应该总是有理由选择懒惰。根据用例的不同,有几种替代方案,并且这种结构肯定是合适的。但不要仅仅因为它很酷就使用它
例如,在其他答案中,我没有得到页面选择示例中的要点。使用Lazy列表选择单个元素可以直接使用委托列表或字典,而无需使用Lazy或简单的switch语句
因此,最明显的选择是
- 直接实例化廉价的数据结构或无论如何都需要的结构
- 在某些算法中需要零到几次的委托
- 某些缓存结构用于在一段时间内不使用时应释放内存的项
- 某种“未来”结构,如任务,在实际使用之前可能已经开始异步初始化,在以后需要该结构的可能性很高的情况下,会消耗空闲CPU时间
- 计算密集型数据结构
- 在某些算法中,如果零概率很大,则需要零到多次
- 数据是某个方法或类的本地数据,在不再使用时可以进行垃圾收集,或者应该在整个程序运行时将数据保存在内存中
Lazy
,主要是因为它在从数据库加载资源时具有并发功能。因此,我摆脱了锁定对象和有争议的锁定模式。
就我而言,ConcurrentDictionary
+Lazy
,感谢@Reed Copsey和他的团队,这是我一天中的价值所在
如下所示。而不是打电话:
MyValue value = dictionary.GetOrAdd(
key,
() => new MyValue(key));
我们将使用ConcurrentDi
MyValue value = dictionary.GetOrAdd(
key,
() => new Lazy<MyValue>(
() => new MyValue(key)))
.Value;