0

私のプロセスは複数のインスタンス (プロセス) と複数のスレッドを実行し、それらすべてが同じデータベースに書き込みます。リクエストが発行されるとすぐに、独自のデータベースに追加されるレコードに対して一意の req id が生成されます。制限事項は次のとおりです。長さは 9 文字を超えることはできず、最初の 6 文字として hhmmss が必要です。最後の 3 桁に ms を使用して 9 文字を完成させることにしました。これはすべて gettimeofday() を使用して行っています。ただし、トラフィックの増加に伴い、1 ミリ秒の間に複数のリクエストが送信されると、衝突のインスタンスが発生するようになりました。これは、gettimeofday() 自体が正確ではないという事実と相まって、衝突数の増加を引き起こしています。私は clock_gettime を使用しようとしましたが、テストすると、次のテストプログラムから観察したように正確ではありません:

  • スレッド化の問題により、静的変数またはグローバル変数を使用できませんでした
  • 連続する必要があるため、乱数を使用できません

どんな助けにも感謝します。

#include <time.h>

int main( int argc, char **argv )
{
    long i;
    struct timespec start, stop;
    double gap;

    clock_gettime( CLOCK_REALTIME, &start);

    for (i =0; i< 123456789 ; i++);

    clock_gettime( CLOCK_REALTIME, &stop);

    gap = ( stop.tv_sec - start.tv_sec ) + ( stop.tv_nsec - start.tv_nsec ) / 1000000;
    printf( "%lf ms\n", gap );
    return 0;
}
4

4 に答える 4

1

あなたが説明しているタイプの問題は、UUID を発行することですでに多かれ少なかれ解決されています。これは、あなたが言及したすべての問題とその他の問題を解決するように設計されたシステムです。

Linux ライブラリ: http://linux.die.net/man/3/uuid

詳細については、http: //en.wikipedia.org/wiki/Universally_unique_identifierをご覧ください。

于 2010-10-13T23:02:21.227 に答える
0

タイム スタンプを一意の ID として使用しても、最低クロック ティック (この場合は 1 ミリ秒) ごとに 1 つのトランザクションのみに制限しない限り、確実に機能することはありません。

9 バイトのうち最初の 6 バイトに時間値を使用することに行き詰まっているため、できるだけ多くの範囲を最後の 3 バイトに収める必要があります。

最後の 3 バイトに ASCII 文字を使用しないで済む場合は、それを避ける必要があります。可能であれば、これらのバイトを 24 ビット整数 (16777216 の範囲) として使用し、各トランザクションでカウンターをインクリメントするようにしてください。gettimeofday が時刻が変更されたことを通知するたびに、0 に戻すことができます。(または、繰り返し SIGALRM を設定して、 gettimeofday を再度呼び出して時間を更新し、24 ビット整数を 0 にするタイミングを通知することもできます)。

これらのバイトに ASCII 印刷可能文字を使用せざるを得ない場合、状況は少し難しくなります。この範囲を拡張する最も簡単な方法は、10 進数ではなく 16 進数を使用することです。これにより、表現可能な範囲が 1000 から 4096 に拡大します。ただし、さらに広い基数を使用すると、より良い結果が得られます。アルファベットの最初の 22 文字を追加すると (16 進数で最初の 6 文字を追加するのと同じ方法で)、32x32x3232768 という値を表すことができます。これは、1 秒あたりのトランザクション数が多いことになります。数字のアルファベットをさらに拡張すると、さらにうまくいく可能性がありますが、一部の文字が値に表示されないように制限したい場合があるため、断片的になります。strtolまたは_strtoul簡単に操作できるほど、プログラミングが容易になる可能性があります。

アプリケーションがマルチスレッド化されている場合は、数値範囲の一部をスレッド ID として使用し、各スレッドが独自のトランザクション カウンターを保持できるようにすることを検討してください。これにより、異なるスレッドによって処理される 2 つのトランザクション間の相対時間を計算することがより困難になりますが、すべてのスレッドが同じメモリ位置をインクリメントする必要がなくなります (ミューテックスまたはセマフォが必要になる場合があります)。

于 2010-10-13T19:51:21.337 に答える
0

一般に、このような負荷の高いシステムで 1 秒未満の解像度でクロック時間を使用することは、とにかく悪い考えです。スレッドはタイムスタンプを取得し、操作の途中でスケジュールが解除されるため、順番が狂っていることがわかります。

物事を一意にエンコードするために残された 3 文字は多くありません。少なくとも、base64 などの別のエンコーディングを使用してみてください。

コンパイラとして使用する場合gcc、非常に効率的な拡張機能としてスレッド ローカル ストレージ (TLS) があります。static変数の前に__thread(またはそのように)接頭辞を付けるだけです。phtreads に制限されている場合は、スレッド固有のキーを取得する手段もありますpthread_get_key。ただし、スレッドのスタックにできるだけ長い情報を保持することをお勧めします。

リクエストのシリアル番号を使用するスレッドごとのカウンターを取得するには

  • これまでの hhmmss タイムスタンプ
  • スレッドを識別するために必要なビット数
  • 上記のスレッドごとのシリアル番号の最後のビットは、 1 秒以上経過した後にのみラップする必要があります

不正行為を行ってyieldいて、同じ秒内にあまりにも多くのリクエストを発行するスレッドである可能性さえあります.

于 2010-10-13T19:51:29.773 に答える
0

起動時に各プロセスの各スレッドに一意の ID を与えることができると思いますが、数百のスレッドがない限り、これは使用可能な 3 文字のうちの 1 文字だけを取ると思います。その後、スレッドごとにローカル カウンターを使用して、最後の 2 文字を設定できます (許容される文字に応じて base64 またはそれ以上を使用して、十分な振幅を取得します)。

この状況で衝突が発生する唯一のケースは、スレッドのカウンターが同じ秒内にラップする場合です。

もちろん、これは汚いハックです。正しい方法は、スレッド/プロセス間でリソースを共有することです。あなたの場合、それは最も簡単な解決策かもしれません。

于 2010-10-13T19:57:29.043 に答える