Когда ленивый груз? - PullRequest
       17

Когда ленивый груз?

9 голосов
/ 13 октября 2011

Я лениво загружаю всех своих участников.Я делал это какое-то время и просто воспринимал ленивую нагрузку как хорошую вещь по номиналу.

Скажем, у нас есть

public class SomeClass
{
   public int anInt;
   public SomeReferenceType member1;

   public SomeClass()
   {
      //initialize members in constructor when needed (lazy load)
      anInt = new int();
      member1 = new SomeReferenceType();
   }
}

Есть ли какие-либо недостатки в таких действиях?Это правильная ленивая схема загрузки?Есть ли смысл лениво загружать тип значения (с современной оперативной памятью это вообще имеет значение)?

После того, что я узнал из ваших ответов, я хотел бы знать, есть ли какая-либо разница между вышеизложенным и этим ...

public class SomeClass
    {
       public int anInt;
       public SomeReferenceType member1 = new SomeReferenceType();

       public SomeClass()
       {

       }
    }

Ответы [ 8 ]

17 голосов
/ 13 октября 2011

Прежде всего, инициализация элемента внутри конструктора не является отложенной загрузкой.

Ленивая загрузка инициализирует элемент при первом запросе.Простой пример в .NET (с некоторой двойной проверкой блокировки, поэтому у нас нет проблем с потоками):

public class SomeClass
{
    private object _lockObj = new object();
    private SomeReferenceType _someProperty;

    public SomeReferenceType SomeProperty
    {
        get
        {
            if(_someProperty== null)
            {
                lock(_lockObj)
                {
                    if(_someProperty== null)
                    {
                        _someProperty= new SomeReferenceType();
                    }
                }
            }
            return _someProperty;
        }
        set { _someProperty = value; }
    }
}

К счастью, если вы используете .NET 4, теперь вы можете использовать Lazy<T> Класс , который решает проблемы для вас и делает все намного проще.

Во-вторых, отложенная загрузка - это хорошая идея, когда у вас много членов, которые могут быть дорогостоящими для загрузки, и выВы уверены, что будете использовать все эти значения.Эта стоимость привела бы к тому, что тип не обязательно медленно создавался для экземпляра.

Ленивая загрузка только ради отложенной загрузки добавляет ненужную сложность к вашему коду и может вызвать проблемы в будущем, если выполняется неправильно (прис резьбой, например).

8 голосов
/ 13 октября 2011

Это не ленивый груз. Это инициализация на строительстве. Обычно в ленивой загрузке мы подразумеваем конструирование элемента при первом обращении к нему.

    private string _someField;

    public string SomeField
    {
        get 
        {
            // we'd also want to do synchronization if multi-threading.
            if (_someField == null)
            {
                _someField = new String('-', 1000000);
            }

            return _someField;
        }
    }

Раньше одним из типичных способов Lazy загрузки была проверка, блокировка, проверка, чтобы не блокировать, если она уже создана, но поскольку два элемента могут пройти проверку и дождаться блокировки Проверяешь снова в замке:

public class SomeClass
{
    private string _someField;

    private readonly object _lazyLock = new object();


    public string SomeField
    {
        get 
        {
            // we'd also want to do synchronization if multi-threading.
            if (_someField == null)
            {
                lock (_lazyLock)
                {
                    if (_someField == null)
                    {
                        _someField = new String('-', 1000000);
                    }
                }
            }

            return _someField;
        }
    }
}

Существуют различные способы сделать это, на самом деле в .NET 4.0 есть тип Lazy<T>, который может помочь вам легко выполнять потоковую ленивую загрузку.

public class SomeClass
{
    private readonly Lazy<string> _someField = new Lazy<string>(() => new string('-', 10000000), true);

    private readonly object _lazyLock = new object();


    public string SomeField
    {
        get
        {
            return _someField.Value;
        }
    }
}

Что касается того, почему, как правило, ленивая загрузка является хорошей схемой, если создаваемый вами объект имеет тенденцию быть дорогим (память или время), и нет никакой гарантии, что он вам понадобится. Если вы достаточно уверены, что он всегда будет использоваться, то вам следует просто создать его прямо.

6 голосов
/ 13 октября 2011

Из кода, который я вижу, вы не выполняете ленивую загрузку.Вы инициализируете элементы в конструкторе, что всегда происходит и происходит очень скоро при жизни экземпляра.

Следовательно, мне интересно, что для вас не ленивая загрузка?

Ленивая загрузка обычно происходит, когда вы инициализируете что-то только при обращении к нему.

ЗдесьНапример, используя .NET 4.0 Lazy класс, который помогает вам в этом, ленивая загрузка:

public class Foo
{
    private Lazy<int> _value = new Lazy<int>(() => 3);

    public int Value { get { return _value.Value; } }
}

Относительно безопасности потока - вы можете передать второй аргумент LazyThreadSafetyMode, который знает два способа указать поток-safety: тот, в котором выполнение метода инициализации может происходить несколько раз, но где все потоки получают значение, которое было создано первым, или тот, где выполнение также защищено от запуска несколько раз.

0 голосов
/ 28 сентября 2018
List<int> number = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        var result = number.Where(x => x % 2 == 0);
        number.Add(20);
        //foreach (int item in result)
        //{
        //    Console.WriteLine("loop1:" + item);
        //}

        foreach (int item in result)
        {
            if (item == 4)
                break;
            Console.WriteLine("loop2:" + item);
        }
        number.Add(40);
        foreach (int item in result)
        {

            Console.WriteLine("loop3:"+item);
        }
        Console.ReadLine();

раскомментируйте первый цикл и посмотрите разницу. Очень пример использования для понимания отсроченного исполнения и отложенной загрузки.

0 голосов
/ 08 августа 2018

Ленивая загрузка - это концепция, при которой мы откладываем загрузку объекта до того момента, когда он нам понадобится.Проще говоря, загрузка объекта по требованию, а не загрузка объектов без необходимости.

Например, рассмотрим приведенный ниже пример, в котором у нас есть простой класс Customer, а в этом классе Customer есть много объектов Order.Внимательно посмотрите на конструктор класса Customer.Когда объект Customer создается, он также загружает объект Order в этот момент.Таким образом, даже если нам нужен или не нужен объект Order, он все равно загружается.

Ссылка на пример

0 голосов
/ 15 сентября 2017

Ленивая загрузка необходима, когда стоимость создания объекта очень высока, а использование объекта очень редко.Итак, это сценарий, в котором стоит реализовать отложенную загрузку.Основная идея отложенной загрузки состоит в том, чтобы загружать объект / данные при необходимости

0 голосов
/ 13 октября 2011

Реальное загруженное с отложенной версией свойство для int может выглядеть примерно так:

private int? _heavyLoadedInt;

public int HeavyLoading
{
    get
    {
        if (_heavyLoadedInt == null)
            _heavyLoadedInt = DoHeavyLoading();
        return _heavyLoadedInt.Value;
    }
}

Теперь, если вы посмотрите на это, вы увидите, что здесь есть некоторые издержки: вы должны сохранитьзначение в обнуляемом (дополнительная память);проверять его на null при каждом доступе и извлекать значение из nullable при каждом доступе.

Если ваше целое число действительно требует серьезных вычислений, тогда эта конструкция имеет смысл.Но new int() - это не тяжелое вычисление, оно просто возвращает 0.Издержки незначительны, но если вы добавите эти накладные расходы к еще более крошечной операции (то есть к чтению целого числа), это не имеет смысла.

0 голосов
/ 13 октября 2011

это не ленивая загрузка.

ленивая загрузка будет означать, что вы просто загружаете значение в момент реального доступа (чего не происходит в инициализаторе)

ленивая загрузка это что-товот так:

private SomeClass _someRef = null;
public SomeClass SomeRef
{
  get
  {
    if(_someRef == null)
    {
       //initialisation just in case of access
       _someRef = new  SomeClass();
    }
    return _someRef;
  }
}
...