2011-08-24 3 views
7

私は同じ秒で複数のWebリクエストを介して呼び出すことができる次のコードを持っています。したがって、私は2番目の+要求がデータベースに当たるのを望んでいませんが、最初の要求が行われるまで待っています。このC#コードをLazy <T>クラスを使用するようにリファクタリングする必要がありますか?

代わりにLazy<T> キーワード クラスを使用するようにこれをリファクタリングする必要がありますか?コードLazy<T>への10回のコールが同時に発生した場合、それらのコールのうち9回は最初のコールが完了するのを待ちますか?

public class ThemeService : IThemeService 
{ 
    private static readonly object SyncLock = new object(); 
    private static IList<Theme> _themes; 
    private readonly IRepository<Theme> _themeRepository; 

    <snip snip snip> 

    #region Implementation of IThemeService 

    public IList<Theme> Find() 
    { 
     if (_themes == null) 
     { 
      lock (SyncLock) 
      { 
       if (_themes == null) 
       { 
        // Load all the themes from the Db. 
        _themes = _themeRepository.Find().ToList(); 
       } 
      } 
     } 

     return _themes; 
    } 

    <sip snip snip> 

    #endregion 
} 
+2

'Lazy 'はキーワードではありません。 – BoltClock

+0

それでは、それは何と呼ばれていますか? –

+0

これは単純にタイプと呼ばれています。具体的には、クラスです。 – BoltClock

答えて

12

はいあなたはMSDNからLazy<T>

を使用することができます。

デフォルトでは、レイジーオブジェクトは、スレッドセーフです。つまり、 コンストラクタがスレッドセーフティの種類を指定していない場合、それが作成するLazy オブジェクトはスレッドセーフです。マルチスレッドのシナリオでは、 スレッドセーフLazy オブジェクトのValueプロパティに最初にアクセスするスレッドは、すべてのスレッドですべてのスレッドのすべてのアクセスに対して初期化します。および すべてのスレッドが同じデータを共有します。したがって、 スレッドがどのオブジェクトを初期化し、競合状態が良性であるかは関係ありません。

はい、それはキーワードではありません - .NETフレームワーククラスでは、怠惰な初期化のために必要なケースを頻繁に公式化し、これをそのまま利用できるので、手動で行う必要はありません。

8

@BrokenGlassが指摘したように、安全です。しかし、私は抵抗し、テストをしなければならなかったことができませんでした...

つだけのスレッドIDが...

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

印刷しかし、一つは速くなるのですか?私が得た結果から...

コードコード億回

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

テストコードの実行100回

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

実行

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

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

試験方法:

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

恐ろしい仕事@ブリュノLM :) –

関連する問題