programing

Lazy는 언제 사용해야 합니까?

batch 2023. 6. 5. 23:43
반응형

Lazy는 언제 사용해야 합니까?

에 대한 이 기사를 찾았습니다.LazyC# 4.0의 게으름게으름

Lazy 객체를 사용하여 최고의 성능을 발휘하는 가장 좋은 방법은 무엇입니까?누가 나에게 실제 응용 프로그램의 실용적인 용도를 알려줄 수 있습니까?즉, 언제 사용해야 합니까?

일반적으로 처음 사용할 때 인스턴스화할 때 사용합니다.이로 인해 항상 비용이 발생하는 대신 필요할 때까지 생성 비용이 지연됩니다.

일반적으로 이것은 객체가 사용될 수 있거나 사용되지 않을 수 있고 객체를 구성하는 비용이 사소한 경우에 선호됩니다.

싱글턴을 사용하는 것을 피하도록 노력해야 합니다. 하지만 만약 필요하다면,Lazy<T>게으르고 스레드 안전한 싱글톤을 쉽게 구현할 수 있습니다.

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

    Singleton()
    {
        // Explicit private constructor to prevent default public constructor.
        ...
    }

    public static Singleton Instance => instanceHolder.Value;
}

게으른 로딩이 유용한 실제 사례로는 엔티티 프레임워크 및 NHibernate와 같은 ORM(객체 관계 매핑)을 들 수 있습니다.

이름, 전화 번호 및 주문에 대한 속성을 가진 엔티티 Customer가 있다고 가정합니다.이름과 전화 번호는 일반 문자열이지만 주문은 고객이 주문한 모든 주문 목록을 반환하는 탐색 속성입니다.

종종 모든 고객의 이름과 전화 번호를 확인하여 고객에게 전화하기를 원할 수도 있습니다.이는 매우 빠르고 간단한 작업이지만, 고객을 생성할 때마다 자동으로 이동하여 복잡한 조인을 수행하여 수천 개의 주문을 반환한다고 가정해 보십시오.가장 나쁜 점은 주문을 사용하지 않을 것이기 때문에 리소스가 완전히 낭비된다는 것입니다!

주문 속성이 게으르면 실제로 필요하지 않는 한 모든 고객의 주문을 가져올 수 없기 때문에 이 위치가 적재를 게을리하기에 완벽합니다.주문 속성이 지속적으로 절전 모드에 있는 동안 필요한 시간에 사용할 수 있도록 고객 개체의 이름과 전화 번호만 얻을 수 있습니다.

사용을 고려하고 있습니다.Lazy<T>내 코드의 성능을 향상시키는 데 도움이 되는 속성(및 코드에 대해 조금 더 자세히 알아보기).언제 사용할 것인지에 대한 답을 찾으러 왔는데, 가는 곳마다 다음과 같은 문구가 있는 것 같습니다.

특히 프로그램의 수명 동안 이러한 생성 또는 실행이 발생하지 않을 수 있는 경우에는 대규모 또는 리소스 집약적인 개체의 생성 또는 리소스 집약적인 작업의 실행을 연기하려면 느린 초기화를 사용합니다.

MSDN Lazy에서클래스

어디에 선을 그어야 할지 몰라서 조금 혼란스럽습니다.예를 들어, 저는 선형 보간법을 상당히 빠른 계산으로 간주하지만, 만약 제가 그것을 할 필요가 없다면 게으른 초기화가 제가 그것을 하는 것을 피하는 데 도움이 될 수 있습니까?

결국 저는 저만의 테스트를 해보기로 결정했고, 그 결과를 여기서 공유하기로 했습니다.불행하게도 저는 이런 종류의 테스트를 하는 데 전문가가 아니기 때문에 개선을 제안하는 의견을 얻게 되어 기쁩니다.

묘사

저의 경우, Lazy Properties가 많은 보간(대부분은 사용되지 않음)을 수행하는 코드의 일부를 개선하는 데 도움이 될 수 있는지 여부에 특히 관심이 있었습니다. 그래서 저는 세 가지 접근 방식을 비교하는 테스트를 만들었습니다.

각 접근 방식에 대해 20개의 테스트 속성(t-properties라고 함)으로 별도의 테스트 클래스를 만들었습니다.

  • GetInterp Class: t 속성을 가져올 때마다 선형 보간을 실행합니다.
  • InitInterp 클래스:생성자의 각 속성에 대해 선형 보간을 실행하여 t-속성을 초기화합니다.겟은 그냥 더블을 반환합니다.
  • InitLazy Class: 속성을 처음 가져올 때 선형 보간이 한 번 실행되도록 t-속성을 Lazy 속성으로 설정합니다.후속 gets는 이미 계산된 이중 값만 반환해야 합니다.

검정 결과는 ms 단위로 측정되며 50번의 인스턴스화 또는 20번의 속성 get의 평균입니다.그런 다음 각 테스트를 5회 실행했습니다.

테스트 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

테스트 2 결과:첫 번째 Get(평균 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

테스트 3 결과:두 번째 Get(평균 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

관찰

GetInterp아무 것도 하지 않기 때문에 예상대로 인스턴스화하는 것이 가장 빠릅니다. InitLazy▁than보다 가 빠릅니다.InitInterp레이지 속성 설정의 오버헤드가 선형 보간 계산보다 빠르다는 것을 의미합니다.하지만, 나는 여기서 약간 혼란스럽습니다. 왜냐하면InitInterp (test 1) 인스턴스화 1)에는 0. 이는 t-stating 20ms( 1)에는 .GetInterp한 번 2에 한 는 0, 두 하는 데는가 소요됩니다.한, 번에 선 보 테 데 가 가 0.28ms두 (테스트 2), 수 테 행 하 번 걸 즉 는 0.1ms 다 3트

그것은 걸린다.InitLazy보다 거의 2배 더 긴GetInterp처음으로 부동산을 얻는 동안.InitInterp인스턴스화 중에 속성을 채웠기 때문에 가장 빠릅니다.(적어도 그렇게 했어야 했는데 왜 단일 선형 보간보다 인스턴스화 결과가 훨씬 빨랐을까요?정확히 언제 이러한 보간을 하고 있습니까?)

안타깝게도 제 테스트에서 자동 코드 최적화가 진행되고 있는 것 같습니다.시간이 걸릴 것입니다.GetInterp두 번째와 같은 시간에 속성을 얻지만 두 번째보다 2배 이상 빠른 것으로 표시됩니다.이 최적화는 다른 수업에도 영향을 미치는 것으로 보이는데, 이 수업들은 모두 시험 3에 대해 거의 같은 시간을 소요하기 때문입니다.그러나 이러한 최적화는 또한 중요한 고려 사항이 될 수 있는 나만의 생산 코드에서도 발생할 수 있습니다.

결론들

일부 결과는 예상대로이지만 코드 최적화로 인해 매우 흥미로운 예상치 못한 결과도 있습니다.생성자에서 많은 작업을 수행하는 것처럼 보이는 클래스의 경우에도 인스턴스화 결과는 이중 속성을 얻는 것에 비해 여전히 생성 속도가 매우 빠를 수 있음을 보여줍니다.이 분야의 전문가들이 좀 더 철저하게 의견을 제시하고 조사할 수는 있겠지만, 제 개인적인 생각은 어떤 종류의 최적화가 그곳에서도 일어날 수 있는지를 검토하기 위해서는 이 테스트를 다시 해야 한다는 것입니다.하지만, 저는 그것을 기대하고 있습니다.InitInterp그게 우리가 가야 할 길일 수도대체 뭐죠?

매튜가 게시한 예를 확대해 보겠습니다.

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; }
    }
}

Lazy가 프레임워크의 일부가 되기 전에는 다음과 같은 방식으로 작업을 수행했을 것입니다.

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

MSDN에서:

Lazy 인스턴스를 사용하여 대규모 또는 리소스 집약적인 개체의 생성 또는 리소스 집약적인 작업의 실행을 연기할 수 있습니다. 특히 프로그램의 수명 동안 이러한 생성 또는 실행이 발생하지 않을 수 있는 경우에는 더욱 그렇습니다.

James Michael Hare의 답변 외에도 Lazy는 스레드 세이프로 값을 초기화합니다.레이지 보기이 클래스에 대한 다양한 유형의 스레드 안전 모드를 설명하는 스레드 안전 모드 열거 MSDN 항목입니다.

Lazy Loading 아키텍처를 이해하려면 이 예를 살펴봐야 합니다.

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");
    }
}

--> 출력 --> 0 1 2

하지만 이 코드가 "리스트"라고 쓰지 않으면.Value.Add(0);"

출력 --> 값이 생성되지 않았습니다.

언급URL : https://stackoverflow.com/questions/6847721/when-should-i-use-lazyt

반응형