C# - System.Lazy

System.Lazy ?

  • System.Lazy 는 지연 초기화를 지원하는 클래스이다. .NET Framework 4.0 에서 추가
  • 사용하는 경우
    • 멀티 스레드 환경에서 공유 리소스의 초기화를 스레드 세이프하게 하고 싶을 때
    • 초기화에 시간이 걸리는(또는 많은 하드웨어 자원을 사용하는) 클래스가 있을 때 이것을 사용할지 안할지 알 수 없는 경우에 사용한다.

간단 예제

  • http://weblogs.asp.net/gunnarpeipman/archive/2009/05/19/net-framework-4-0-using-system-lazy-lt-t-gt.aspx
static void Main(string[] args)
{
    var lazyString = new Lazy<string>(
        () =>
        {
            // Here you can do some complex processing
            // and then return a value.
     Console.Write("Inside lazy loader");
            return "Lazy loading!";
        });
    Console.Write("Is value created: ");
    Console.WriteLine(lazyString.IsValueCreated);

    Console.Write("Value: ");
    Console.WriteLine(lazyString.Value);

    Console.Write("Value again: ");
    Console.WriteLine(lazyString.Value);

    Console.Write("Is value created: ");
    Console.WriteLine(lazyString.IsValueCreated);

    Console.WriteLine("Press any key to continue ...");
    Console.ReadLine();
}
Is value created: False
Inside lazy loader
Value: Lazy loading!
Value again: Lazy loading!
Is value created: True
Press any key to continue …

멀티스레드에서 공유 리소스 초기화 일반 vs Lazy

  • double-checked locking
class Hoge
{
  volatile HeavyObject _heavy;
  readonly object _lock = new object();

  public HeavyObject Heavy
  {
    get
    {
      if (_heavy == null)
      {
        lock (_lock)
        {
          if (_heavy == null)
          {
            _heavy = new HeavyObject();
          }
        }
      }

      return _heavy;
    }
  }
}
  • race-to-initialize
class Hoge
{
  volatile HeavyObject _heavy;

  public HeavyObject Heavy
  {
    get
    {
      if (_heavy == null)
      {
        var heavy = new HeavyObject();
        Interlocked.CompareExchange(ref _heavy, heavy, null);
      }

      return _heavy;
    }
  }
}
  • Lazy 사용
var lazy1 = new Lazy<HeavyObject>(() => new HeavyObject(), true); 

//또는

var lazy1 = new Lazy<HeavyObject>(() => new HeavyObject(), LazyThreadSafetyMode.ExecutionAndPublication); 


class Hoge
{
  Lazy<HeavyObject> _heavy = new Lazy<HeavyObject>(() => new HeavyObject(), LazyThreadSafetyMode.ExecutionAndPublication);

  public HeavyObject Heavy
  {
    get
    {
      return _heavy.Value;
    }
  }
}

이 글은 2019-03-27에 작성되었습니다.