Lazy <T>的缺点?

ean*_*son 48 c# mef lazy-evaluation

我最近在整个应用程序中开始使用Lazy,我想知道在使用时是否有任何明显的消极方面需要考虑Lazy<T>

我试图Lazy<T>尽可能经常使用,主要是为了帮助减少加载但非活动插件的内存占用.

Gle*_*eno 19

我将对我的评论进行一些扩展,其内容如下:

我刚开始使用Lazy,发现它通常表明设计不好; 或者程序员的懒惰.另外,一个缺点是你必须对scoped up变量保持警惕,并创建适当的闭包.

例如,我曾经用来Lazy<T>创建用户可以在我的(无会话)MVC应用程序中看到的页面.它是一个指导向导,因此用户可能希望转到随机的一步.在进行握手时,会创建一个Lazy<Page>对象数组,如果用户指定为步骤,则会评估该确切页面.我发现它提供了良好的性能,但有些方面我不喜欢,例如我的许多foreach构造现在看起来像这样:

foreach(var something in somethings){
     var somethingClosure = something;
     list.Add(new Lazy<Page>(() => new Page(somethingClosure));
} 
Run Code Online (Sandbox Code Playgroud)

即你必须非常积极地处理关闭问题.否则,我认为存储lambda并在需要时对其进行评估并不会造成如此糟糕的性能损失.

另一方面,这可能表明程序员是一个Lazy<Programmer>,在某种意义上你不想现在不考虑你的程序,而是在需要时让正确的逻辑进行评估,例如在我的例子中 - 而不是建立那个数组,我可以弄清楚具体请求的页面是什么; 但我选择懒惰,并采取一切措施.

编辑

对我来说,Lazy<T>在使用并发时也会有一些诡计.例如,有ThreadLocal<T>一些场景,以及针对特定多线程场景的几种标志配置.您可以在msdn上阅读更多内容.

  • 这本身并不是"Lazy <T>"的问题.相反,它就是你如何使用它. (3认同)
  • @Anton,是的; 而我的猜想是,Lazy <>有时*有问题,因为你可以选择不寻找更好的解决方案.鉴于这个选项,你可能会选择适合的东西. (3认同)

CSh*_*per 9

在我看来,你应该总是有理由选择懒惰.根据使用情况,有几种替代方案,并且肯定存在这种结构合适的情况.但不要仅仅因为它很酷而使用它.

例如,我在其他一个答案中没有得到页面选择示例中的要点.使用Lazy列表来选择单个元素可以直接使用委托列表或字典来完成,而无需使用Lazy或使用简单的switch语句.

所以最明显的选择是

  • 直接实例化无论如何需要的廉价数据结构或结构
  • 代表在某些算法中需要零到几次的事情
  • 一些缓存结构,用于在不使用一段时间后应释放内存的项目
  • 某些类型的"未来"结构,如任务,在实际使用消耗空闲CPU时间之前已经开始异步初始化,如果概率非常高,以后将需要结构

与此相反,懒惰通常适用于

  • 计算密集的数据结构
  • 在零情况具有显着概率的某些算法中需要零次或多次
  • 并且数据对于某些方法或类是本地的,并且可以在不再使用时进行垃圾收集,或者数据应该保存在内存中以用于整个程序的运行时


小智 7

这不是一个消极的方面,但对于懒惰的人来说是一个骗局:).

延迟初始化器就像静态初始化器.他们跑了一次.如果抛出异常,则会缓存异常,并且对.Value的后续调用将抛出相同的异常.这是设计的,并在文档中提到... http://msdn.microsoft.com/en-us/library/dd642329.aspx:

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
    {

    }
}
Run Code Online (Sandbox Code Playgroud)


Max*_*ets 5

我开始使用Lazy<T>主要是因为它在从数据库加载资源时具有并发功能.因此,我摆脱了锁定对象和可论证的锁定模式.在我的情况下,ConcurrentDictionary+ Lazy作为我的一天的价值,感谢@Reed Copsey和他的博客文章

这看起来如下.而不是打电话:

MyValue value = dictionary.GetOrAdd(
                             key, 
                             () => new MyValue(key));
Run Code Online (Sandbox Code Playgroud)

我们改为使用ConcurrentDictionary>,并写:

MyValue value = dictionary.GetOrAdd(
                             key, 
                             () => new Lazy<MyValue>(
                                 () => new MyValue(key)))
                          .Value;
Run Code Online (Sandbox Code Playgroud)

Lazy<T>到目前为止没有注意到的缺点.