12

パフォーマンスの問題が発生しています。潜在的な原因の 1 つは、揮発性のシングルトンを集中的に使用することです。特定のコードは次の形式です

class foo {
  static volatile instance;
  static object l = new object();

  public static foo Instance {
    if (instance == null)
      lock(l) {
        if (instance == null)
          instance = new foo();
      }

    return foo();
  }
}

これは 8 ウェイ ボックスで実行されており、1 秒あたり 500,000 の速度でコンテキストが切り替わっています。典型的なシステム リソースは問題ありません - 25% の CPU 使用率、25% のメモリ使用率、低 IO、ページングなしなど。

揮発性フィールドを使用すると、メモリバリアまたは何らかの種類の CPU キャッシュのリロードが誘発されますか? それとも、そのフィールドのみについて、毎回メインメモリを追いかけますか?

4

6 に答える 6

4

lockメモリバリアを誘発するため、常にロック内のインスタンスにアクセスしている場合、揮発性は必要ありません。

このサイトによると:

C# volatile キーワードは、取得と解放のセマンティクスを実装します。これは、読み取り時の読み取りメモリ バリアと書き込み時の書き込みメモリ バリアを意味します。

于 2009-06-16T17:06:09.093 に答える
3

volatileが実行しないことの1つは、コンテキストスイッチを引き起こすことです。1秒あたり500,000のコンテキストスイッチが表示されている場合は、スレッドが何かをブロックしており、volatileが原因ではないことを意味します。

于 2009-06-19T17:39:44.220 に答える
1

悲しいことに、シングルトンはほぼすべてのことで悪いラップを取ります:)

これは私の専門分野ではありませんが、私が知る限り、コンパイラ/ランタイムが最適化のために (変数への) 読み取り/書き込みを並べ替えないこと以外に、volatile について特別なことは何もありません。

編集:私は訂正しました。揮発性はメモリバリアを導入するだけでなく、何が起こるか (そして付随的にパフォーマンス) は、関与する特定の CPU に大きく依存します。http://dotnetframeworkplanet.blogspot.com/2008/11/volatile-field-and-memory-barrier-look.htmlを参照してください。

これが、ロックが必要な理由です。

すでに回答されている/されていない可能性のある質問:

  1. あなたのシングルトンインスタンスは実際に何をしていますか? インスタンスコードをリファクタリングする必要があるかもしれません...
  2. 実行中のプロセスのスレッド数は? スレッド数が異常に多い場合、8 ウェイ ボックスは役に立ちません。
  3. 予想よりも高い場合、その理由は何ですか?
  4. システム上で他に何が実行されていますか?
  5. パフォーマンスの問題は一貫していますか?
于 2009-06-16T17:37:24.423 に答える
0

シングルトンにvolatileを使用する必要はありません。これは、1回だけ設定し、コードをロックすると設定されるためです。詳細については、シングルトンに関するJonSkeetの記事を参照してください。

于 2009-06-16T17:56:45.020 に答える
0

簡単な答えは、はい、メモリバリアを作成します(単一の変数だけでなく、すべてをフラッシュしてメインメモリに移動します)が、いいえ、コンテキスト切り替えの原因にはなりません。

また、他の人が述べたように、ここでは揮発性が必要だとは思いません。

于 2015-05-29T18:27:28.710 に答える
0

ここでの例では、揮発性は「スローダウン」の対象にはなりません。ただし、lock() は、特にロックの競合が多い場合に、カーネルへの膨大なラウンドトリップを伴う可能性があります。

この場合、シングルトンをロックする必要はまったくありません。

class Foo {
  static Foo instance = new Foo();
  public static Foo FooInstance() {
    return instance ;
  }
}

もちろん、「インスタンス」が多くの異なるスレッドで使用されている場合でも、Foo のすべてのメソッド/プロパティが読み取り専用でない限り、その Foo を変更するものはすべて lock() する必要があります。例えば

 class Foo {
      static Foo instance = new Foo();
      object l = new object();
      int doesntChange = 42;
      int canChange = 123;
      public static Foo FooInstance() {
        return instance ;
      }
      public void Update(int newVal) {
         lock(l) { // you'll get a lot of trouble without this lock if several threads accesses the same FOO. Atleast if they later on read that variable 
            canChange = newVal;
         }

      public int GetFixedVal() {
         return doesntChange; //no need for a lock. the doesntChange is effectivly read only
      }
    }
于 2009-06-16T17:42:28.507 に答える