Windows/C# システムレベルの連番ジェネレータ?
-
09-09-2019 - |
質問
管理されたシステムレベルの連続番号ジェネレータはありますか?DateTime.Now.Ticks は実行しません。これは、私が実行している操作がティックごとに複数回発生する場合があるためです。
要件の説明:
- プロセスに依存しない - これにアクセスするプロセスは実際には 1 つだけです。
- パフォーマンスは重要です!これは、広告サーバー上のインプレッションをログに記録するために使用され、1 秒あたり 1,000 に達する可能性があります
次のいずれかである必要があります。
- ティックごとにリセットする 4 バイトの連続番号
- 12 バイトの連続番号 - 基本的に DateTime に 4 バイトの粒度を追加します。
解決
これを目的としたものはありませんが、使用できます System.Diagnostics.PerformanceCounter. 。レジストリを使用することもできますが、プロセス全体で読み取り/書き込みアクセスをシリアル化する必要があります。
System.Diagnostics.PerformanceCounter pc
= new System.Diagnostics.PerformanceCounter("SeqCounter", "SeqInstance");
long myVal=pc.Increment();
編集
考えれば考えるほど、これは良い解決策になるかもしれないと思います。インクリメントは、システム上のすべてのプロセスにわたって機能するアトミック操作を通じてカウンターを 1 ずつ増やします。
編集
編集によると、パフォーマンス カウンターの使用はお勧めしません。パフォーマンス カウンターは、複数のプロセスを調整する方法でした。内部実装がどのようにコーディングされているかわかりません。
なぜ静的変数を使用してインクリメントできないのでしょうか?これをスレッドセーフにしたい場合は、何かをロックする必要があります。
System.Threading.Interlocked.Increment
ご参考までに:32 ビット システムで長いバージョンを使用する場合、必ずしもスレッド セーフではありません。
私が使用した実装を示す編集 (DS):
public static class Int32Sequencer
{
private static Int32 lastSequence = Int32.MinValue;
private static Object lockObject = new Object();
public static Int32 GetNextSequence()
{
lock (lockObject)
{
unchecked { lastSequence++; }
return lastSequence;
}
}
}
他のヒント
Guid は限りなく近いものですが、それらは「一意」であり、必ずしも連続しているわけではありません。システムレベルで複数のプロセスにわたってシーケンシャルにしたい場合は、おそらく独自のプロセスを作成する必要があります。
編集:
さて、新しい要件から、次のように仮定します。
- 作業を実行する必要があるプロセスは 1 つだけです
- データベースに追加しています
そこで私がお勧めするのは次のとおりです。
- プロセスの起動時に、DB に最後の (最大) 値をクエリします (存在しない場合は 0)。
- DB 行ごとに単純な Long および Increment を使用します。データ レートが高いため、バッチで挿入する必要があるでしょう。
それで済むはずです。単純にする。これにはロックがなく、起動時にわずかな (無視できる) ヒットが発生し、DB には連続番号が含まれます。このアルゴリズムは、実行しているプロセスが 1 つだけである限り、プロセスに依存しません。
私は、最も近いものは、私はあなたが認識していると確信しているとして、せいぜい部分的にシーケンシャルであるGUID、だと思います。
SQL Serverのいくつかの詳細を与えるこっちの記事があります: SQLでのシーケンシャルGUIDさんこの技術のサーバーは、GUIDののランダム性に起因するページ分割を最小化するために使用されます。たぶん、このリンクはあなたにいくつかのヒントやアイデアを与えるだろう。
あなたが探しているものについてもう少し詳しく知る必要があると思います。質問を少し明確にしていただけますか。特にサービスは...
- すべてのプロセス、1 つのプロセス、または特定のユーザーにわたって作業する必要がありますか?
- 番号は一意である必要がありますか、それとも単に連続している必要がありますか?
ご質問によると、お探しのアイテムがいくつかあるようです。
システム上のすべてのプロセスにわたって一連の数値グループが必要である
私の知る限り、そのようなサービスは存在しません。書くのはかなり簡単ですが、すべてのプロセスで動作させるのは難しいです。
システム上のすべてのプロセスにわたって、一意の一連の番号グループが必要
最初の質問とは少し異なります。そのようなサービスは実装が不可能なので存在しません。値が最終的にオーバーフローして重複した番号が残るため、組み込みデータ型を使用して一意の連続番号を保証する方法はありません。
システム内で一意の値を取得する方法が必要
他の何人かのユーザーが述べているように、最良の選択は System.Guid インスタンスです。Guid.NewGuid() を使用して新しいものを作成できます。ほとんどすべての目的において、それらは一意であると見なされますが、連続的ではありません。
私は単純に、安全のためのデータベースオプションが好きです。あなたがが十分なメモリを搭載したサーバー間の帯域幅のアロットでモンスターSQLサーバーをインストールしていることを確認します。これと同様のシステムは、(私もプログラマになる前)と、それは非常に危険なだった私が今まで働いた最初の企業で実施されました。あなたはこれを拡張する戦いがあります。
別のオプションは、あなたのコードにシングルトンの機能を実装するために...唯一のアプリケーションドメインがそれを呼び出すされます提供されることになります。データベースの旅をしているよりも少し速いかもしれ。あなたは何2を組み合わせることについて...データベースリソース許可に書き込み、その後スピードのシングルトンを実行します。
....とにかくデータベースにこのようなものをログに記録しようとしているしかし、もし シーケンシャルな要件は、その強力でない場合は、ここでも、GUIDはあなたの最善の策だろう。
ロックせずに単一のシーケンシャルシリーズを取得する方法はありません。パフォーマンスカウンタ、静的変数、何でも - - あなたが次の値に割り当てるために使用しているもののメカニズムは重要ではありません。二つのスレッドが同時に次の値を必要とするとき、一方が他方に待たなければならないが、
私はどうしたいまず最初に、それぞれを繰り返し、そのようなダニエル・シャファーが掲載一つとして、ロックインクリメント機能と呼ばれる多数のスレッドを生み出したテストプログラムを作成しています。それはあなたがあなたのアプリケーションがスラッシュを開始しきい値を見つけるようになる - それはどこに、何をやってよりMonitor.Enter
で待っているより多くの時間を費やしています。
それが問題であることが判明した場合 - と私はあなたが話しているボリュームが本当であれば、それはすることを賭けると思います - あなたは、各スレッドは、あなたがマークすることによって行うことができ、独自のシーケンシャルカウンターを維持すべきですThreadStaticAttribute
とカウンタフィールド。あなたは、スレッドのIDとカウンターの組み合わせのオフ一意の識別子を生成することができます。
このアプローチは機能しません。そして、あなたはおそらく、あなたは、耐久性に優れたストレージにスレッドカウンターを記述する必要はありませんように、化合物のIDのアプリケーションの起動カウント部を作りたいです。 (あなたがこれをしなかった場合は、サーバーを再起動したときにスレッドが再びゼロにカウンターを生成開始すると、アプリケーションは、以前のインスタンスと同じIDを持つスレッドを作成した場合は、重複したIDを取得したいです。)
これは明らかに(、もっと重要なのは、テストをか)書くのは簡単ではないので、私は間違いなくそれがまず必要だということを証明お勧めします。