Easy Thread-Safe Random Values in C# – Tim Coreyとのディープダイブ
乱数を生成することはすべての開発者が出会うタスクの一つです。 単純なランダム値を作成することは些細に思えるかもしれませんが、特にマルチスレッド環境でC#のスレッドセーフ性を確保することは難しいことがあります。 "C#でのスレッドセーフランダム値の簡単生成"というビデオで、Tim CoreyはC#で乱数がどのように機能するか、古いメソッドの落とし穴、そして複数のスレッドを使う際にスレッドセーフ性を確保する方法について探求します。
この記事では、Timの説明に従い、スレッドセーフランダム番号生成の詳細、ベストプラクティス、および関連する同期技術について見ていきます。
Introduction to Random Values and Thread Safety in C
Timは、C#でのランダム値生成は一般的に簡単であると指摘します。 しかし、物事を行うにはさまざまな方法があり、コードが1つのスレッド内で実行されるか、多くのスレッドで同時に実行されるかによって選択は変わります。 Timは、このビデオが開発者のための迅速で実用的なガイドとして設計されており、簡単な例を挙げつつスレッドセーフ性に関する深い洞察を提供することを強調しています。
彼は、Visual Studio 2026プレビューで.NET 10を使用したコンソールアプリケーションで例を示しますが、視聴者にVisual Studio 2022および.NET 9でも同じコードが動作することを保証します。何かに従って実行したい人のために、Timは説明欄にソースコードを提供しています。
Traditional Random Number Generation in C
Timは、Randomクラスを使用して乱数を生成する古典的なアプローチを示し始めます。 彼はインスタンスRNG1とRNG2の2つを作成し、Next()でランダム整数を生成する方法を示します。
Random rng1 = new();
Random rng2 = new();
for(int i = 0; i < 10; i++)
{
int output1 = rng1.Next(1, 101);
int output2 = rng2.Next(1, 101);
Console.WriteLine($"Random 1: {output1}, Random 2: {output2}");
}このコードを実行するとそれぞれのインスタンスで異なる数字が生成されますが、このコードはスレッドセーフではありませんとTimは説明します。 マルチスレッド環境では、同じRandomインスタンスに2つのスレッドがアクセスした場合、Randomオブジェクトの内部状態が同時にアクセスされるため予期しない値や重複が発生する可能性があります。
スレッドセーフ性を確保する一つの方法は、スレッドごとに1つのRandomインスタンスを使用することだと彼は指摘します。 これはワーカースレッド、非同期メソッド、または複数のスレッドでコードを同時に実行する可能性のある任意の状況で重要です。 適切な同期なしにスレッド間で同じインスタンスを共有すると、レースコンディション、不正な値、または不適切に管理された場合はデッドロックにつながることがあります。
予測可能なランダム番号のためのシードの使用
次にTimはシードの使用法を示します。 シードは、生成される数字のシーケンスを決定する開始値です。 たとえば、両方のRNG1とRNG2に対してシードとして25を使用すると:
Random rng1 = new(25);
Random rng2 = new(25);両方のインスタンスが同じシーケンスの数字を生成します。 Timは、これはバグではなく機能であり、再現性が求められるシナリオで役立つことを強調しています。 これは、単体テストや、複数のスレッド間でランダムな値のシーケンスを再現する必要があるマルチスレッドプログラムのデバッグに役立ちます。
Random.Sharedによるスレッドセーフランダム数
TimはRandom.Sharedを紹介し、ランダム数を生成するための最新でスレッドセーフな方法です。 手動でインスタンスを作成する代わりに、Random.Sharedは、並行アクセスを自動で扱うスタティックで共有されているリソースです:
int output1 = Random.Shared.Next();
int output2 = Random.Shared.Next();このアプローチでは、ロック、スタティックコンストラクタ、または共有リソースを心配する必要がありません。 .NETに組み込まれているスレッドセーフコレクションとRandom.Sharedインスタンスにより、複数のスレッドを安全に同時に使用することができます。
Random.Sharedの利点
Timはこのアプローチのいくつかの利点を説明します:
インスタンス化が不要:スレッドごとに別個のインスタンスを必要としません。
デフォルトでスレッドセーフ:並行タスクやワーカースレッドでの使用に安全です。
- シンプルなAPI:整数、小数、および配列シャッフルさえもサポートします。
彼は1つの制限に注意を促します:シードを設定できないため、シーケンスは予測可能ではありません。 同じ順序の数値が必要なシナリオでは、シード付きの個別インスタンスを使用する必要があります。
複雑なコードでのスレッドセーフ性の確保
Random.Sharedは内部でスレッドセーフ性を扱いますが、Timの例により、C#における一般的なスレッドセーフ性技術について議論することができます。 より複雑なコードやマルチスレッド環境では、レースコンディションを回避し、データの整合性を確保するために正しく同期する必要があることが多いです。 一般的な技術には次のようなものがあります:
ロックステートメント:複数のスレッドが同時に重要なセクションにアクセスするのを防ぎます。
静的メンバーと静的コンストラクタ:安全に共有リソースを初期化するために使用できます。
スレッドセーフコレクション:ConcurrentQueue, ConcurrentStack, ConcurrentDictionaryなどのクラスは安全な並行アクセスを可能にします。
- 相互排除(Mutex/Monitor):コードのセクションを一度に1つのスレッドのみが実行できるようにします。
Timは、ほとんどの乱数のケースで、Random.Sharedはこれらの技術を必要としなくしますが、共有リソースを持つマルチスレッドアプリケーションでは、デッドロックや予期しない値を避けるためにこれらの方法が不可欠であると説明します。
Tim Coreyからの実用的なガイドライン
Timはマルチスレッドアプリケーションで安全に乱数を使用するための明確なガイドラインを提供しています:
Random.Sharedを使用して簡潔に:パフォーマンスが重要な場合、ランダム値が必要なときに理想的です。
再現性のためにシード付きインスタンスを使用:トラッキングするデータやマルチスレッド環境でのデバッグが必要な場合に必要です。
暗号化におけるランダムの使用を避ける:セキュリティのために、暗号化ライブラリを使用してください。
- スレッドセーフ性の基本を理解する:複数のスレッドがあなたのコードにアクセスした場合、適切に同期を実装する必要があります。
彼は、Random.Sharedが複数のスレッドからミリ秒あたり数百万回の呼び出しが行われても機能し、その効率的な並行アクセスを処理することを開発者に保証します。
Conclusion: Safe and Simple Random Numbers in C
Tim Coreyのビデオは、C#でのスレッドセーフランダム数の生成が多くの開発者が思っているよりも容易であることを示しています。Random.Sharedを使用することで、マルチスレッド環境に関連する多くの落とし穴を避けることができます。 予測可能なシーケンスが必要な場合は、シード付きの個別インスタンスを使用することで信頼できるアプローチが提供されます。
スレッドセーフ性、重要なセクション、および同期技術を理解していれば、マルチスレッドアプリケーションでもコードを適切に正しく実行し続けることができます。 Timの指導に従って、開発者はスレッドセーフなコードを、ワーカースレッド、非同期メソッド、並列タスクに自信を持って書くことができ、競合状態、デッドロック、予期しない値を心配する必要がありません。

