ホームページ バックエンド開発 C#.Net チュートリアル C#シングルトンパターンの実装と性能比較例

C#シングルトンパターンの実装と性能比較例

May 16, 2018 pm 05:08 PM
.net

この記事では、主に C# シングルトン モードの実装とパフォーマンスの比較に関する関連情報を紹介します。6 つの実装方法を詳しく紹介します。必要な方は参考にしてください。

単一のケースは、次のことができるクラスのみを指します。 1 つのインスタンスを持つ (C# では、より正確には、各 AppDomain に 1 つのインスタンスしか持てないクラス) は、ソフトウェア エンジニアリングで最も一般的に使用されるパターンの 1 つであり、最初のユーザーはこのクラスのインスタンスを作成した後、このクラスを使用する場合は、以前に作成されたインスタンスのみを使用でき、新しいインスタンスを作成することはできません。通常、C# でのシングルトン実装メソッドがいくつか導入されており、それらの間のスレッドの安全性とパフォーマンスの違いが異なります。シングルトンを実装するにはさまざまな方法がありますが、最も単純な実装 (非遅延ロード、非スレッド セーフ、低効率) から、遅延ロード、スレッド セーフ、効率的な実装まで、さまざまな方法があります。これらにはすべて、いくつかの基本的な共通点があります:

シングルトン クラスはすべて、引数のないプライベート コンストラクターを 1 つだけ持ちます

  • クラス宣言はシールされています (必須ではありません)

  • クラスには静的変数があります。作成されたインスタンスへの参照を保持します

  • シングルトン クラスは、作成されたインスタンスへの参照を返す静的メソッドまたはプロパティを提供します (例: GetInstance)

  • 複数の実装

1 つの非スレッド セーフティ

//Bad code! Do not use!
public sealed class Singleton
{
  private static Singleton instance = null;
  private Singleton()
  {
  }

  public static Singleton instance
  {
    get
    {
      if (instance == null)
      {
        instance = new Singleton();
      }
      return instance;
    }
  }
}
ログイン後にコピー

このメソッドはスレッドセーフではありません。if (instance == null) の場合、同時に 2 つのスレッドが実行され、2 つの異なるインスタンスが作成され、以前に取得されたインスタンスが置き換えられます。

2 番目の単純なスレッドセーフ実装

public sealed class Singleton
{
  private static Singleton instance = null;
  private static readonly object padlock = new object();

  Singleton()
  {
  }

  public static Singleton Instance
  {
    get
    {
      lock (padlock)
      {
        if (instance == null)
        {
          instance = new Singleton();
        }
        return instance;
      }
    }
  }
}
ログイン後にコピー

実装 1 と比較して、このバージョンでは、インスタンスを呼び出す前にインスタンスにロックを追加する必要があるため、実装 1 ではスレッドの競合が回避されます。ただし、インスタンスが呼び出されるたびにロックが使用されるため、この実装ではパフォーマンスがある程度低下します

ここでは新しいプライベート オブジェクトを使用していることに注意してください。シングルトンを直接ロックするのではなく、インスタンスの南京錠を使用してロック操作を実装します。これにより、潜在的なリスクが生じる可能性があります。この型はパブリックであるため、理論的には、これを直接ロックするとパフォーマンス上の問題が発生し、さらにはデッドロックが発生する可能性があります。 : C# では、同じスレッドでオブジェクトをロックすることができますが、異なるスレッドが同時にロックされると、スレッド待ちが発生したり、深刻なデッドロック状態が発生したりする可能性があります。そのため、ロックを使用する場合は、ロックを使用するようにしてください。ロックするクラス内のプライベート変数を選択すると、上記の状況が発生するのを回避できます

3重検証スレッドセーフティ実装

public sealed calss Singleton
{
  private static Singleton instance = null;
  private static readonly object padlock = new object();

  Singleton()
  {
  }

  public static Singleton Instance
  {
    get
    {
      if (instance == null)
      {
        lock (padlock)
        {
          if (instance == null)
          {
            instance = new Singleton();
          }
        }
      }
      return instance;
    }
  } 
}
ログイン後にコピー

この実装は、スレッドの安全性を確保しながら、インスタンスが呼び出されるたびにロック操作も回避します。 、ある程度の時間を節約できます。

ただし、この実装には欠点もあります。

1 は Java では機能しません。 (具体的な理由については原文をご覧ください。ここではあまり理解できません)

2 プログラマーは自分で実装するときに間違いを犯しがちです。このモードでコードを独自に変更する場合は、ダブル チェックのロジックが比較的複雑で、考えが不十分なために間違いを犯しやすいため、十分に注意してください。

ロックを使用しない 4 つのスレッドセーフな実装

public sealed class Singleton
{
  //在Singleton第一次被调用时会执行instance的初始化
  private static readonly Singleton instance = new Singleton();

  //Explicit static consturctor to tell C# compiler 
  //not to mark type as beforefieldinit
  static Singleton()
  {
  }

  private Singleton()
  {
  }

  public static Singleton Instance
  {
    get
    {
      return instance;
    }
  }
}
ログイン後にコピー

この実装は非常にシンプルでロックを使用しませんが、依然としてスレッドセーフです。ここでは、静的な読み取り専用のシングルトン インスタンスが使用されます。シングルトンが初めて呼び出されたときに、新しいインスタンスが作成されます。新しいインスタンスを作成するときのスレッドの安全性の保証は、.NET によって直接制御されます。また、AppDomaining 内で 1 回だけ作成されます。

この実装にはいくつかの欠点もあります:

1 インスタンスが作成されるタイミングは不明であり、Singleton への呼び出しにより事前にインスタンスが作成されます

2 静的コンストラクターの循環呼び出し。 2 つのクラス A と B があり、A の静的コンストラクターが B を呼び出し、B の静的コンストラクターが A を呼び出す場合、これら 2 つは循環呼び出しを形成し、プログラムが重大なクラッシュを引き起こす可能性があります。

3 Singleton の静的コンストラクターを手動で追加して、Singleton 型が beforefieldinit 属性で自動的に追加されないようにして、Singleton が初めて呼び出されたときにインスタンスが作成されるようにする必要があります。

4readonly 属性は実行時に変更できません。プログラムの実行中にインスタンスを破棄して新しいインスタンスを再作成する必要がある場合、この実装方法は満たされません。

5 つの完全な遅延インスタンス化

public sealed class Singleton
{
  private Singleton()
  {
  }

  public static Singleton Instance 
  {
    get
    {
      return Nested.instance;
    }
  }

  private class Nested
  {
    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static Nested()
    {
    }

    internal static readonly Singleton instance = new Singleton();
  }
}
ログイン後にコピー

実装 5 は、実装 4 のラッパーです。これにより、インスタンスが Instance の get メソッドでのみ呼び出され、最初の呼び出しの前にのみ初期化されることが保証されます。これは、遅延読み込みを保証する実装 4 のバージョンです。

Six は .NET4 の Lazy 型を使用します

public sealed class Singleton
{
  private static readonly Lazy<Singleton> lazy = new Lazy<Singleton>(() => new Singleton());

  public static Singleton Instance 
  {
    get 
    {
      return lazy.Value;
    }
  }

  private Singleton()
  {
  }
}
ログイン後にコピー

.NET4 以降では、最も単純なコードを使用してシングルトンの遅延読み込み特性を保証します。

パフォーマンスの違い

前の実装では、スレッドの安全性とコードの遅延読み込みを強調しました。ただし、実際の使用では、シングルトン クラスの初期化に時間がかからない場合、または初期化シーケンスによってバグが発生しない場合、初期化にかかる時間は無視できるため、遅延初期化は必要ありません。

実際の使用シナリオでは、シングルトン インスタンスが頻繁に呼び出される場合 (ループ内など)、スレッド セーフの確保によって生じるパフォーマンスの消費はより注目に値します。

これらの実装のパフォーマンスを比較するために、これらの実装のシングルトンを 9 億回ループし、毎回インスタンス メソッドを呼び出して count++ 操作を実行し、100 万ごとに出力して、環境を実行するという小さなテストを作成しました。 MBP 上の Visual Studio for Mac です。結果は次のとおりです。

完全ではありません 145725つの実現ははいはい14295が6つのyesyes22875概要

スレッド セーフティ 遅延読み込み テスト実行時間 (ミリ秒)
実装 1 いいえ はい 15532
実績2 45803
3を実現する 15953
4を実現する
テスト方法は厳密ではありませんが、メソッド2が最も時間がかかるため、それは最も時間がかかることがわかります。毎回 lock を呼び出す必要があり、他のものよりもほぼ 3 倍多くなります。 2 位は .NET Lazy 型を使用した実装で、他の実装より約 2 分の 1 多くなっています。残りの 4 つは明らかな違いはありません。
一般に、上記で説明したさまざまなシングルトン実装方法は、今日のコンピューターのパフォーマンスではそれほど違いはありません。特に大量の同時呼び出しでインスタンスを呼び出す必要がない限り、パフォーマンスを考慮する必要があります。ロックの質問。

一般の開発者にとって、シングルトンを実装するには方法 2 または方法 6 を使用するだけで十分です。方法 4 と 5 では、C# の実行プロセスを十分に理解し、実装する際にある程度の習熟度が必要です。保存にはまだ制限があります。

引用

この記事の大部分は、C# でのシングルトン パターンの実装を翻訳したものであり、私自身の理解もいくつか追加されています。これは、静的読み取り専用フィールドの初期化と静的コンストラクターの初期化を検索したときに見つけたものです。ここで 2 人の著者に感謝の意を表したいと思います。

以上がC#シングルトンパターンの実装と性能比較例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

C# の雇用の見通しはどのようなものですか? C# の雇用の見通しはどのようなものですか? Oct 19, 2023 am 11:02 AM

初心者でも経験豊富なプロフェッショナルでも、C# をマスターすることでキャリアへの道が開かれます。

いくつかの .NET オープンソース AI および LLM 関連プロジェクト フレームワークを共有する いくつかの .NET オープンソース AI および LLM 関連プロジェクト フレームワークを共有する May 06, 2024 pm 04:43 PM

現在、人工知能(AI)技術の開発は本格化しており、さまざまな分野で大きな可能性と影響力を発揮しています。本日、Dayao は、参考にしていただけるよう、4 つの .NET オープン ソース AI モデル LLM 関連プロジェクト フレームワークを共有します。 https://github.com/YSGStudyHards/DotNetGuide/blob/main/docs/DotNet/DotNetProjectPicks.mdSemanticKernelSemanticKernel は、OpenAI、Azure などの大規模言語モデル (LLM) を統合するように設計されたオープン ソース ソフトウェア開発キット (SDK) です。

開発者向けの .NET パフォーマンス最適化テクノロジ 開発者向けの .NET パフォーマンス最適化テクノロジ Sep 12, 2023 am 10:43 AM

.NET 開発者は、高品質のソフトウェアを提供するために機能とパフォーマンスを最適化することの重要性を認識する必要があります。提供されたリソースを巧みに活用し、Web サイトの読み込み時間を短縮することで、ユーザーに快適なエクスペリエンスを提供するだけでなく、インフラストラクチャのコストも削減できます。

Java フレームワークと .NET フレームワークのパフォーマンスの違い Java フレームワークと .NET フレームワークのパフォーマンスの違い Jun 03, 2024 am 09:19 AM

同時実行性の高いリクエスト処理の点では、.NETASP.NETCoreWebAPI は JavaSpringMVC よりも優れたパフォーマンスを発揮します。その理由としては、AOT の早期コンパイルにより起動時間が短縮され、開発者がオブジェクト メモリの割り当てと解放を行うため、より洗練されたメモリ管理が行われます。

c#.netインタビューの質問と回答:専門知識を高める c#.netインタビューの質問と回答:専門知識を高める Apr 07, 2025 am 12:01 AM

C#.NETインタビューの質問と回答には、基本的な知識、コアの概念、高度な使用が含まれます。 1)基本知識:C#は、Microsoftが開発したオブジェクト指向言語であり、主に.NETフレームワークで使用されています。 2)コアの概念:委任とイベントは動的な結合方法を可能にし、LINQは強力なクエリ関数を提供します。 3)高度な使用:非同期プログラミングは応答性を向上させ、式ツリーは動的コード構造に使用されます。

高度なC#.NETチュートリアル:次のシニア開発者インタビューをエース 高度なC#.NETチュートリアル:次のシニア開発者インタビューをエース Apr 08, 2025 am 12:06 AM

C#シニア開発者とのインタビューでは、非同期プログラミング、LINQ、.NETフレームワークの内部作業原則などのコア知識をマスターする必要があります。 1.非同期プログラミングは、非同期を通じて操作を簡素化し、アプリケーションの応答性を向上させるのを待ちます。 2.LinqはSQLスタイルでデータを操作し、パフォーマンスに注意を払います。 3.ネットフレームワークのCLRはメモリを管理し、ガベージコレクションに注意して使用する必要があります。

C#.NET:コアの概念とプログラミングの基礎を探る C#.NET:コアの概念とプログラミングの基礎を探る Apr 10, 2025 am 09:32 AM

C#は、Microsoftによって開発された最新のオブジェクト指向プログラミング言語であり、.NETフレームワークの一部として開発されています。 1.C#は、カプセル化、継承、多型を含むオブジェクト指向プログラミング(OOP)をサポートしています。 2。C#の非同期プログラミングは非同期を通じて実装され、適用応答性を向上させるためにキーワードを待ちます。 3. LINQを使用してデータ収集を簡潔に処理します。 4.一般的なエラーには、null参照の例外と、範囲外の例外インデックスが含まれます。デバッグスキルには、デバッガーと例外処理の使用が含まれます。 5.パフォーマンスの最適化には、StringBuilderの使用と、不必要な梱包とボクシングの回避が含まれます。

.NET内のC#コード:プログラミングプロセスの調査 .NET内のC#コード:プログラミングプロセスの調査 Apr 12, 2025 am 12:02 AM

.NETでのC#のプログラミングプロセスには、次の手順が含まれます。1)C#コードの作成、2)中間言語(IL)にコンパイルし、3).NETランタイム(CLR)によって実行される。 .NETのC#の利点は、デスクトップアプリケーションからWebサービスまでのさまざまな開発シナリオに適した、最新の構文、強力なタイプシステム、および.NETフレームワークとの緊密な統合です。

See all articles