1

我们真的需要System.Lazy吗?假设我的类库有 100 个静态类,每个静态类平均使用 100 个静态 System.Lazys = 10000 System.Lazys,当使用我的类库的程序启动时必须启动?

我的意思是我们通常不只使用 1 个类库,比如说我们导入 15 个 .dll,每个都有大量静态 System.Lazys .. 我很确定启动所有这些 System.Lazys 需要很长时间,更不用说它也会囤积大量内存(因为每个都有自己的 System.Func 让我们把它放在每个 50 字节 = 500kb 的内存中)

所以我想知道..最好以“旧”方式来做(比如使用布尔值来跟踪是否启动了某些东西)

4

3 回答 3

7

您应该仅在以下情况下使用Lazy:1) 很有可能不需要该实例,以及 2) 启动该实例的成本高到足以证明开销是合理的。

如果一个类中有 100 个静态惰性成员,那么几乎可以肯定你做错了。

于 2011-04-23T19:03:30.150 回答
3

正如其他人所说,如果您需要这种延迟初始化,您将面临更大的问题。

但无论如何,只是为了展示你应该如何自己处理这个问题:在做出假设之前测量。

下面的程序(受ayende启发)测量创建和初始化一个简单地分配一个新对象的 Lazy() 实例的开销。

我机器上的输出:

Created 583599 objects in 00:00:01.0000117
Created 679939 objects in 00:00:01.0039926
Created 688751 objects in 00:00:01.0000013
Created 678244 objects in 00:00:01.0000018
Created 682506 objects in 00:00:01.0000018
Created and initialized 516400 lazy objects in 00:00:01.0000018
Created and initialized 526585 lazy objects in 00:00:01.0000049
Created and initialized 519425 lazy objects in 00:00:01.0000018
Created and initialized 514477 lazy objects in 00:00:01.0000022
Created and initialized 523544 lazy objects in 00:00:01.0005176
Performance loss: 21,5091944284387 %

不要由此得出一般性结论,因为性能问题很多时候是针对当前情况的。

但是正如您所看到的,通过实例化对象Lazy与简单地分配对象的开销new相对较小,因为这Lazy通常应该在延迟实例化有用的情况下(即昂贵,并且构造的对象很有可能不被实际需要)

class Program
{
static void Main(string[] args)
    {
        var sequence = Enumerable.Range(1, 5);

        var q1 = from s in sequence
                 select GenerateSimpleObjects();

        var q2 = from s in sequence
                 select GenerateAndInitializeLazies();

        var m1 = q1.Average();
        var m2 = q2.Average();

        Console.WriteLine("Performance loss: {0} %", 100 - 100 * m2/m1);

    }

    static void GenerateSimpleObjects()
    {
        var sp = Stopwatch.StartNew();

        int i = 0;
        while (sp.ElapsedMilliseconds < 1000)
        {
            new object();
            i++;
        }
        sp.Stop();
        Console.WriteLine("Created {0} objects in {1}", i, sp.Elapsed);
    }


    static void GenerateAndInitializeLazies()
    {
        var sp = Stopwatch.StartNew();

        int i = 0;
        while (sp.ElapsedMilliseconds < 1000)
        {
            var l = new Lazy<object>(() => new object());
            var o = l.Value;
            i++;
        }
        sp.Stop();
        Console.WriteLine("Created and initialized {0} lazy objects in {1}", i, sp.Elapsed);
    }
}
于 2011-04-23T20:00:15.953 回答
2

Lazy<T>意味着谨慎使用,在图中延迟加载对象是有意义的。也就是说,对于可能不需要但可能需要的对象,并且获取它们的成本很高。

为此,它们是一个很好的解决方案。

如果您知道您将使用所有对象,请不要使用Lazy<T>.

于 2011-04-23T19:04:16.997 回答