0
public class MyConfigurationData
{
   public double[] Data1 { get; set; }
   public double[] Data2 { get; set; }
}
public class MyClass
{
   private static object SyncObject = new object();
   private static MyConfigurationData = null;
   private static MyClass()
   {
      lock(SyncObject)
      {
         //Initialize Configuration Data
         //This operation is bit slow as it needs to query the DB to retreive configuration data
      }
   }
   public static MyMethodWhichNeedsConfigurationData()
   {
      lock(SyncObject)
      {
          //Multilple threads can call this method
          //I lock only to an extent where I attempt to read the configuration data
      }
   }
}

私のアプリケーションでは、構成データを 1 回だけ作成し、それを数回使用する必要があります。つまり、一度書いて何度も読む。また、書き込み操作が完了するまで読み取りが行われないようにしたかったのです。つまり、MyConfigurationData を NULL として読み取りたくありません。

私が知っているのは、静的コンストラクターが AppDomain で 1 回だけ呼び出されることです。しかし、構成データを準備しているときに、スレッドがこのデータを読み取ろうとした場合、どうすれば同期を効果的に行うことができますか? 最後に、読み取り操作のパフォーマンスを改善したいと考えました。

ロックフリーの方法で目標を実装できますか?

4

3 に答える 3

4

MSDNから:

静的コンストラクターは、静的データを初期化するため、または一度だけ実行する必要がある特定のアクションを実行するために使用されます。最初のインスタンスが作成される前、または静的メンバーが参照される前に、自動的に呼び出されます。

したがって、コードで使用する必要はありませんlock。実際にはスレッドセーフです。参照される前に静的コンストラクターが呼び出されMyMethodWhichNeedsConfigurationDataます。

public class MyClass
{
   private static MyConfigurationData = null;
   private static MyClass()
   {
   }

   public static MyMethodWhichNeedsConfigurationData()
   {
   }
}
于 2012-09-11T07:00:35.270 に答える
2

データを読み取るだけであれば、すでにスレッドセーフになっているはずです。読み取りだけの場合、スレッドセーフでないデータ構造はほとんどありません(明らかな反例には、遅延読み込みが含まれる場合があります)。静的コンストラクターはランタイムによって自動的に同期されるため、「構成データの初期化」ステップを実行する複数のスレッドについて心配する必要はありません。

したがって、データが変更されない限り、あなたはすでに安全です。また、不変のインターフェースの背後にデータを隠すことで、間違えにくくすることもできます。

public class ConfigurationData {
    // or some similar immutable API...
    public double GetData1(int index) { return data1[index]; }
    public double GetData2(int index) { return data2[index]; }

    private readonly double[] data1, data2;

    public ConfigurationData(double[] data1, double[] data2) {
        this.data1 = data1;
        this.data2 = data2;
    }
}

次に、ロックは必要ありません。

public class MyClass
{
   private static MyConfigurationData;
   private static MyClass()
   {
     //Initialize Configuration Data
       MyConfigurationData = ...
     //This operation is bit slow as it needs to query the DB to retreive configuration data
   }
   public static MyMethodWhichNeedsConfigurationData()
   {          //Multilple threads can call this method
      var config = MyConfigurationData;

   }
}

ロックを解除すると並列性が向上することに注意してください。生のシングルスレッドのパフォーマンスは変わりません。

つまり、一般的に静的データに対してアドバイスする必要があります。テストが非常に難しくなり、ニーズが変化した場合にマルチテナンシーなどを行うのが難しくなります。単一の構成インスタンスを持つ方が賢明かもしれませんが、それを何らかの形式のcontextとしてシステムに渡します。ただし、どちらのアプローチも問題なく使用できます。これは、注意すべき点にすぎません。

于 2012-09-11T07:04:28.403 に答える
1

シングルトン パターンを使用し、クラスのインスタンスを返す「GetInstance」メソッドに構成初期化ロジックを配置する必要があると思います。

この方法では、読み取り用のロック メカニズムは必要ありません。

于 2012-09-11T07:02:01.823 に答える