Should this C# code be refactored to use the Lazy<T> class instead?

喜欢而已 提交于 2019-12-04 03:59:03

Yes you can use Lazy<T>

From MSDN:

By default, Lazy objects are thread-safe. That is, if the constructor does not specify the kind of thread safety, the Lazy objects it creates are thread-safe. In multithreaded scenarios, the first thread to access the Value property of a thread-safe Lazy object initializes it for all subsequent accesses on all threads, and all threads share the same data. Therefore, it does not matter which thread initializes the object, and race conditions are benign.

And yes, it's not a keyword - its a .NET framework class that formalizes the often required use case for lazy initialization and offers this out of the box so you don't have to do it "manually".

As @BrokenGlass pointed out it is safe. But I couldn't resist and had to make a test...

Only one thread id is printed...

private static Lazy<int> lazyInt;

// make it slow
private int fib()
{
    Thread.Sleep(1000);
    return 0;
}

public void Test()
{
    // when run prints the thread id
    lazyInt = new Lazy<int>(
        () =>
        {
            Debug.WriteLine("ID: {0} ", Thread.CurrentThread.ManagedThreadId);
            return fib();
        });

    var t1 = new Thread(() => { var x = lazyInt.Value; });
    var t2 = new Thread(() => { var x = lazyInt.Value; });
    var t3 = new Thread(() => { var x = lazyInt.Value; });

    t1.Start();
    t2.Start();
    t3.Start();

    t1.Join();
    t2.Join();
    t3.Join();
}

But, which one is faster? From the results I got...

Executing the code 100 times

[   Lazy: 00:00:01.003   ]
[  Field: 00:00:01.000   ]

Executing the code 100000000 times

[   Lazy: 00:00:10.516   ]
[  Field: 00:00:17.969   ]

Test code:

Performance.Test("Lazy", TestAmount, false,
    () =>
    {
        var laz = lazyInt.Value;
    });

Performance.Test("Field", TestAmount, false,
    () =>
    {
        var laz = FieldInt;
    });

Test method:

public static void Test(string name, decimal times, bool precompile, Action fn)
{
    if (precompile)
    {
        fn();
    }

    GC.Collect();
    Thread.Sleep(2000);

    var sw = new Stopwatch();

    sw.Start();

    for (decimal i = 0; i < times; ++i)
    {
        fn();
    }

    sw.Stop();

    Console.WriteLine("[{0,15}: {1,-15}]", name, new DateTime(sw.Elapsed.Ticks).ToString("HH:mm:ss.fff"));
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!