2

管理されたシステムレベルの連番ジェネレーターはありますか? DateTime.Now.Ticks は機能しません。これは、私が行っている操作がティックごとに複数回発生することがあるためです。


要件の説明:

  • プロセスにとらわれない - これにアクセスするプロセスは実際には 1 つだけです。
  • パフォーマンスは重要です。これは、広告サーバーでインプレッションを記録するために使用され、1k/秒に達する可能性があります

次のいずれかである必要があります。

  • ティックごとにリセットされる 4 バイトの連番
  • 12 バイトの連番 - 基本的に DateTime に 4 バイトの粒度を追加
4

7 に答える 7

6

これを意図したものはありませんが、 System.Diagnostics.PerformanceCounterを使用できます。レジストリを使用することもできますが、プロセス全体で読み取り/書き込みアクセスをシリアル化する必要があります。

System.Diagnostics.PerformanceCounter pc 
    = new System.Diagnostics.PerformanceCounter("SeqCounter", "SeqInstance");
long myVal=pc.Increment();

編集

考えれば考えるほど、これは素晴らしい解決策になると思います。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;
        }
    }
}
于 2009-04-14T14:13:38.470 に答える
1

Guid は可能な限り近いものですが、それらは「一意」であり、必ずしも連続しているわけではありません。システム レベルで複数のプロセス間でシーケンシャルが本当に必要な場合は、おそらく独自のロールを作成する必要があります。

編集:

わかりましたので、あなたの新しい要件から、次のように仮定します。

  1. 作業を行う必要があるのは 1 つのプロセスだけです
  2. データベースに追加しています

そこで、私がお勧めするのは次のとおりです。

  1. プロセスの開始時に、最後の (最大の) 値 (存在しない場合は 0) を DB に照会します。
  2. DB 行ごとに単純な long とインクリメントを使用します。データレートが高いため、バッチで挿入する必要があります。

それはそれを行う必要があります。複雑にしないでおく。これにはロックがなく、起動時にわずかな (無視できる) ヒットがあり、DB に連番があります。このアルゴリズムは、実行中のプロセスが 1 つだけである限り、プロセスに依存しません。

于 2009-04-14T14:12:49.830 に答える
0

安全のためにデータベースオプションが好きです。ただし、十分なメモリを備えたサーバー間に帯域幅を割り当てたモンスターSQLサーバーをインストールしてください。これに似たシステムは、私が(プログラマーになる前に)働いた最初の会社で実装されており、非常に危険でした。あなたはこれを拡大縮小するために戦うかもしれません。

もう1つのオプションは、コードにシングルトン関数を実装することです...1つのアプリケーションドメインのみがそれを呼び出す場合。データベーストリップを実行するよりも少し速い場合があります。ただし、とにかくこのようなものをデータベースに記録する場合は、2つを組み合わせてどうでしょうか...速度を上げるためにシングルトンを実行し、リソースが許せばデータベースに書き込みます。

繰り返しになりますが、順次要件がそれほど強くない場合は、GUIDが最善の策です。

于 2009-04-14T15:26:03.600 に答える
0

あなたが探しているものについて、もう少し知る必要があると思います。質問を少し明確にしていただけますか。特にサービスは...

  • すべてのプロセス、1 つのプロセス、または特定のユーザーで作業する必要がありますか?
  • 番号は一意である必要がありますか、それとも単に連続している必要がありますか?

ご質問によると、お探しのアイテムがいくつかあるようです。

システム上のすべてのプロセスにわたって一連の番号のグループが必要

AFAIK、そのようなサービスは存在しません。書くのはかなり簡単なはずですが、すべてのプロセスで機能させるのは難しいです。

システム上のすべてのプロセスで一意の一連の番号グループが必要

最初の質問のわずかなバリエーション。そのようなサービスは、実装が不可能であるため存在しません。値が最終的にオーバーフローして重複した番号が残るため、組み込みのデータ型を使用して一意の連続番号を保証する方法はありません。

システム内で一意の値を取得する方法が必要

他の何人かのユーザーが言及しているように、最良の選択は System.Guid インスタンスです。Guid.NewGuid() を使用して新しいものを作成できます。ほとんどすべての目的で、それらは一意であると見なすことができますが、連続的ではありません。

于 2009-04-14T14:19:34.167 に答える
0

最も近いのは GUID だと思います。ご存知のように、これはせいぜい部分的にしかシーケンシャルではありません。

于 2009-04-14T14:12:16.930 に答える
0

SQL Server の詳細を示す記事がここにあります。 SQL Server の順次 GUIDこの手法は、GUID のランダム性によるページ分割を最小限に抑えるために使用されます。おそらく、このリンクがヒントやアイデアを提供してくれるでしょう。

于 2009-04-14T14:24:22.050 に答える
0

ロックせずに単一のシーケンシャル シリーズを取得する方法はありません。次の値を割り当てるために使用するメカニズム (パフォーマンス カウンター、静的変数など) は関係ありません。2 つのスレッドが同時に次の値を必要とする場合、一方が他方を待たなければなりません。

私が最初に行うことは、Daniel Schaffer が投稿したようなロックインクリメント関数を繰り返し呼び出す多数のスレッドを生成するテスト プログラムを作成することです。これにより、アプリケーションがスラッシングし始めるしきい値、つまり他の処理よりも待機に多くの時間を費やしているしきい値を見つけることができますMonitor.Enter

それが問題であることが判明した場合-そして、あなたが話しているボリュームが本物であるなら、そうなるに違いありません-各スレッドに独自のシーケンシャルカウンターを維持させる必要があります。これは、カウンターフィールドをマークすることで実行できますとThreadStaticAttribute。次に、スレッドの ID とカウンターの組み合わせから一意の識別子を生成できます。

スレッドプールを使用していない場合、このアプローチは機能しません (カウンターが属するスレッドが停止するとカウンターが停止するため)。また、スレッド カウンターを永続的なストレージに書き込む必要がないように、アプリケーションの起動カウントを複合 ID の一部にしたい場合もあります。(これを行わないと、サーバーを再起動したときに、スレッドは再びゼロからカウンターの生成を開始し、アプリケーションが以前のインスタンスと同じ ID を持つスレッドを作成すると、重複した識別子が取得されます。)

これを書くこと (または、もっと重要なことに、テストすること) は明らかに簡単ではないので、最初にそれが必要であることを証明することを強くお勧めします。

于 2009-04-14T19:03:06.403 に答える