我什么时候应该使用懒惰 <T> ?

本文翻译自:When should I use Lazy?

I found this article about Lazy : Laziness in C# 4.0 – Lazy 我发现了有关Lazy这篇文章: C#4.0中的懒惰–懒惰

What is the best practice to have best performance using Lazy objects? 使用惰性对象具有最佳性能的最佳实践是什么? Can someone point me to a practical use in a real application? 有人可以指出我在实际应用中的实际用途吗? In other words, when should I use it? 换句话说,什么时候应该使用它?


#1楼

参考:https://stackoom.com/question/SjP7/我什么时候应该使用懒惰-T


#2楼

A great real-world example of where lazy loading comes in handy is with ORM's (Object Relation Mappers) such as Entity Framework and NHibernate. 延迟加载非常有用的一个现实世界的好例子是使用ORM(对象关系映射器),例如Entity Framework和NHibernate。

Say you have an entity Customer which has properties for Name, PhoneNumber, and Orders. 假设您有一个实体Customer,该实体具有Name,PhoneNumber和Orders的属性。 Name and PhoneNumber are regular strings but Orders is a navigation property that returns a list of every order the customer ever made. Name和PhoneNumber是常规字符串,但是Orders是一个导航属性,它返回客户曾经做过的每个订单的列表。

You often might want to go through all your customer's and get their name and phone number to call them. 您通常可能需要遍历所有客户,并获取他们的姓名和电话号码以致电给他们。 This is a very quick and simple task, but imagine if each time you created a customer it automatically went and did a complex join to return thousands of orders. 这是一个非常快速和简单的任务,但是想像一下,如果您每次创建一个客户,它都会自动进行并执行复杂的联接以返回数千个订单。 The worst part is that you aren't even going to use the orders so it is a complete waste of resources! 最糟糕的是,您甚至都不会使用这些订单,因此完全浪费了资源!

This is the perfect place for lazy loading because if the Order property is lazy it will not go fetch all the customer's order unless you actually need them. 这是延迟加载的理想场所,因为如果Order属性是延迟的,除非您确实需要,否则它将不会获取所有客户的订单。 You can enumerate the Customer objects getting only their Name and Phone Number while the Order property is patiently sleeping, ready for when you need it. 您可以枚举在Order属性耐心地睡眠时,Customer对象仅获得其名称和电话号码,并在需要时准备就绪。


#3楼

Just to point onto the example posted by Mathew 只是指出Mathew发布的示例

public sealed class Singleton
{
    // Because Singleton's constructor is private, we must explicitly
    // give the Lazy<Singleton> a delegate for creating the Singleton.
    private static readonly Lazy<Singleton> instanceHolder =
        new Lazy<Singleton>(() => new Singleton());

    private Singleton()
    {
        ...
    }

    public static Singleton Instance
    {
        get { return instanceHolder.Value; }
    }
}

before the Lazy was born we would have done it this way: 在懒惰者出生之前,我们可以这样进行:

private static object lockingObject = new object();
public static LazySample InstanceCreation()
{
    if(lazilyInitObject == null)
    {
         lock (lockingObject)
         {
              if(lazilyInitObject == null)
              {
                   lazilyInitObject = new LazySample ();
              }
         }
    }
    return lazilyInitObject ;
}

#4楼

I have been considering using Lazy<T> properties to help improve the performance of my own code (and to learn a bit more about it). 我一直在考虑使用Lazy<T>属性来帮助改善我自己的代码的性能(并进一步了解它)。 I came here looking for answers about when to use it but it seems that everywhere I go there are phrases like: 我来这里是为了寻找有关何时使用它的答案,但似乎我走到哪里都有类似的短语:

Use lazy initialization to defer the creation of a large or resource-intensive object, or the execution of a resource-intensive task, particularly when such creation or execution might not occur during the lifetime of the program. 使用惰性初始化可以推迟大型对象或资源密集型对象的创建或资源密集型任务的执行,尤其是在程序生命周期中可能不会发生此类创建或执行时。

from MSDN Lazy<T> Class MSDN Lazy <T>类

I am left a bit confused because I am not sure where to draw the line. 我有点困惑,因为我不确定在哪里划界线。 For example, I consider linear interpolation as a fairly quick computation but if I don't need to do it then can lazy initialisation help me to avoid doing it and is it worth it? 例如,我认为线性插值是一种相当快速的计算,但是如果我不需要这样做,那么惰性初始化可以帮助我避免这样做,这值得吗?

In the end I decided to try my own test and I thought I would share the results here. 最后,我决定尝试自己的测试,并认为我会在这里分享结果。 Unfortunately I am not really an expert at doing these sort of tests and so I am happy to get comments that suggest improvements. 不幸的是,我并不是真正从事此类测试的专家,因此,我很高兴收到提出改进建议的意见。

Description 描述

For my case, I was particularly interested to see if Lazy Properties could help improve a part of my code that does a lot of interpolation (most of it being unused) and so I have created a test that compared 3 approaches. 对于我的情况,我特别感兴趣的是看看Lazy Properties是否可以帮助改进我的代码中进行大量插值的部分(大部分未使用),因此我创建了一个比较3种方法的测试。

I created a separate test class with 20 test properties (lets call them t-properties) for each approach. 我为每种方法创建了一个单独的测试类,该类具有20个测试属性(我们称其为t属性)。

  • GetInterp Class: Runs linear interpolation every time a t-property is got. GetInterp类:每次获得t属性时都运行线性插值。
  • InitInterp Class: Initialises the t-properties by running the linear interpolation for each one in the constructor. InitInterp类:通过对构造函数中的每个插值运行线性插值来初始化t属性。 The get just returns a double. get只会返回一个双精度值。
  • InitLazy Class: Sets up the t-properties as Lazy properties so that linear interpolation is run once when the property is first got. InitLazy类:将t属性设置为Lazy属性,以便在首次获得该属性时运行一次线性插值。 Subsequent gets should just return an already calculated double. 随后的获取应该只返回已经计算出的double。

The test results are measured in ms and are the average of 50 instantiations or 20 property gets. 测试结果以毫秒为单位,是50个实例或20个属性获取值的平均值。 Each test was then run 5 times. 然后每个测试运行5次。

Test 1 Results: Instantiation (average of 50 instantiations) 测试1结果:实例化(平均50个实例化)

 Class 1 2 3 4 5 Avg % ------------------------------------------------------------------------ GetInterp 0.005668 0.005722 0.006704 0.006652 0.005572 0.0060636 6.72 InitInterp 0.08481 0.084908 0.099328 0.098626 0.083774 0.0902892 100.00 InitLazy 0.058436 0.05891 0.068046 0.068108 0.060648 0.0628296 69.59 

Test 2 Results: First Get (average of 20 property gets) 测试2结果:首次获得(平均20个属性获得)

 Class 1 2 3 4 5 Avg % ------------------------------------------------------------------------ GetInterp 0.263 0.268725 0.31373 0.263745 0.279675 0.277775 54.38 InitInterp 0.16316 0.161845 0.18675 0.163535 0.173625 0.169783 33.24 InitLazy 0.46932 0.55299 0.54726 0.47878 0.505635 0.510797 100.00 

Test 3 Results: Second Get (average of 20 property gets) 测试3结果:第二次获取(平均20个属性获取)

 Class 1 2 3 4 5 Avg % ------------------------------------------------------------------------ GetInterp 0.08184 0.129325 0.112035 0.097575 0.098695 0.103894 85.30 InitInterp 0.102755 0.128865 0.111335 0.10137 0.106045 0.110074 90.37 InitLazy 0.19603 0.105715 0.107975 0.10034 0.098935 0.121799 100.00 

Observations 观察结果

GetInterp is fastest to instantiate as expected because its not doing anything. GetInterp最快可以按预期实例化,因为它没有执行任何操作。 InitLazy is faster to instantiate than InitInterp suggesting that the overhead in setting up lazy properties is faster than my linear interpolation calculation. InitLazy实例化速度比InitInterp实例化快,这表明设置惰性属性的开销比我的线性插值计算要快。 However, I am a bit confused here because InitInterp should be doing 20 linear interpolations (to set up it's t-properties) but it is only taking 0.09 ms to instantiate (test 1), compared to GetInterp which takes 0.28 ms to do just one linear interpolation the first time (test 2), and 0.1 ms to do it the second time (test 3). 但是,我在这里有点困惑,因为InitInterp应该执行20个线性插值(以设置其t属性),但是实例化(测试1)只需要0.09毫秒,而GetInterp只需0.29毫秒即可完成一个实例化(测试1)。第一次进行线性插值(测试2),第二次进行0.1mm的线性插值(测试3)。

It takes InitLazy almost 2 times longer than GetInterp to get a property the first time, while InitInterp is the fastest, because it populated its properties during instantiation. 首次获取属性需要InitLazy几乎比GetInterp长2倍,而InitInterp最快,因为它在实例化期间填充了其属性。 (At least that is what it should have done but why was it's instantiation result so much quicker than a single linear interpolation? When exactly is it doing these interpolations?) (至少那是应该做的,但是为什么它的实例化结果比单个线性插值要快得多?什么时候才进行这些插值?)

Unfortunately it looks like there is some automatic code optimisation going on in my tests. 不幸的是,我的测试中似乎正在进行一些自动代码优化。 It should take GetInterp the same time to get a property the first time as it does the second time, but it is showing as more than 2x faster. 第一次获取属性应该与第二次获取GetInterp的时间相同,但是显示速度要快2倍以上。 It looks like this optimisation is also affecting the other classes as well since they are all taking about the same amount of time for test 3. However, such optimisations may also take place in my own production code which may also be an important consideration. 看起来这种优化也正在影响其他类,因为它们都花费了相同的时间进行测试3。但是,这种优化也可能发生在我自己的生产代码中,这可能也是一个重要的考虑因素。

Conclusions 结论

While some results are as expected, there are also some very interesting unexpected results probably due to code optimisations. 尽管某些结果符合预期,但由于代码优化,还有一些非常有趣的意外结果。 Even for classes that look like they are doing a lot of work in the constructor, the instantiation results show that they may still be very quick to create, compared to getting a double property. 即使对于看起来像在构造函数中完成大量工作的类,实例化结果也表明,与获得double属性相比,它们的创建速度仍然非常快。 While experts in this field may be able to comment and investigate more thoroughly, my personal feeling is that I need to do this test again but on my production code in order to examine what sort of optimisations may be taking place there too. 虽然该领域的专家可以发表评论并进行更彻底的调查,但我个人的感觉是我需要再次进行此测试,但需要对生产代码进行检查,以检查在那里可能还会进行哪种优化。 However, I am expecting that InitInterp may be the way to go. 但是,我期望InitInterp可能是要走的路。


#5楼

You should look this example to understand Lazy Loading architecture 您应该看一下这个例子,以了解懒加载架构

private readonly Lazy<List<int>> list = new Lazy<List<int>>(() =>
{
    List<int> configList = new List<int>(Thread.CurrentThread.ManagedThreadId);
    return configList;
});
public void Execute()
{
    list.Value.Add(0);
    if (list.IsValueCreated)
    {
        list.Value.Add(1);
        list.Value.Add(2);

        foreach (var item in list.Value)
        {
            Console.WriteLine(item);
        }
    }
    else
    {
        Console.WriteLine("Value not created");
    }
}

--> output --> 0 1 2 ->输出-> 0 1 2

but if this code dont write "list.Value.Add(0);" 但是如果这段代码没有写“ list.Value.Add(0);”

output --> Value not created 输出->未创建值


#6楼

You typically use it when you want to instantiate something the first time its actually used. 通常,当您想在第一次实际使用某个实例时实例化它。 This delays the cost of creating it till if/when it's needed instead of always incurring the cost. 这将创建它的成本延迟到需要时/而不是始终产生成本。

Usually this is preferable when the object may or may not be used and the cost of constructing it is non-trivial. 通常,当可以使用或不使用该对象并且构造它的成本很重要时,这是优选的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值