32

コンピューティング クラスターで、コードの一部のインスタンス (2000 インスタンス程度) を複数同時に実行しようとしています。それが機能する方法は、ジョブをサブミットすると、ノードが頻繁に開くときにクラスターがそれらを実行し、ノードごとに複数のジョブが実行されます。これは、時間シードを使用する乱数生成で、かなりの数のインスタンスに対して同じ値を生成するようです。

代わりに使用できる簡単な代替手段はありますか? 再現性と安全性は重要ではなく、ユニークなシードの迅速な生成が重要です。これに対する最も簡単なアプローチは何でしょうか。可能であれば、クロスプラットフォームのアプローチが適しています。

4

10 に答える 10

28

命令はrdtscかなり信頼できる (そしてランダムな) シードです。

Windows では、__rdtsc()組み込み関数を介してアクセスできます。

GNU C では、次の方法でアクセスできます。

unsigned long long rdtsc(){
    unsigned int lo,hi;
    __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
    return ((unsigned long long)hi << 32) | lo;
}

この命令は、プロセッサの電源がオンになってからの疑似サイクルの合計を測定します。今日のマシンの周波数が高いことを考えると、2 つのプロセッサが同時に起動し、同じ速度でクロックされている場合でも、それらが同じ値を返す可能性はほとんどありません。

于 2011-10-01T01:44:42.847 に答える
5
unsigned seed;

read(open("/dev/urandom", O_RDONLY), &seed, sizeof seed);
srand(seed); // IRL, check for errors, close the fd, etc...

より良い乱数ジェネレーターもお勧めします。

于 2012-04-22T18:20:48.380 に答える
5

一意のシードを取得するには、PID と時間の組み合わせで十分です。100% クロスプラットフォームではありませんがgetpid(3)、*nix プラットフォームとGetProcessIdWindows では 99.9% の可能性があります。このようなものが動作するはずです:

srand((time(NULL) & 0xFFFF) | (getpid() << 16));

*nix システムからデータを読み取ることもできますが/dev/urandom、Windows には同等のものはありません。

于 2011-10-01T02:04:13.947 に答える
5

他のプロセスを起動するプロセスがあると思います。シードに渡して使用します。次に、そのマスタープロセスに乱数を渡して、各プロセスがシードとして使用するようにすることができます。そうすれば、実際には任意のシードが 1 つだけ選択されます...そのために時間を使うことができます。

他のプロセスを起動するマスタープロセスがない場合、各プロセスに少なくとも一意のインデックスがある場合、できることは、1 つのプロセスに一連の乱数をメモリ (共有メモリの場合) またはファイルに生成させることです。 (共有ディスクの場合)次に、各プロセスにインデックス番目の乱数を取り出してシードとして使用させます。

単一のシードからの一連の乱数ほど、シードを均等に分散させるものはありません。

于 2011-10-01T01:59:33.213 に答える
1

C std lib time()関数から秒単位で測定されるストレートタイムの代わりに、プロセッサのカウンターを使用できますか?ほとんどのプロセッサにはフリーランニングティックカウントがあります。たとえば、x86/x64にはタイムスタンプカウンターがあります。

タイムスタンプカウンタは、Pentium以降のすべてのx86プロセッサに存在する64ビットレジスタです。リセット後のティック数をカウントします。

(このページには、さまざまなプラットフォームでこのカウンターにアクセスするための多くの方法もあります-gcc / ms visual c / etc)

タイムスタンプカウンターには欠陥がないわけではなく、プロセッサー間で同期されない可能性があることに注意してください(おそらくアプリケーションを気にしないでしょう)。また、省電力機能によってプロセッサのクロックがアップまたはダウンする場合があります(ここでも気にしないでしょう)。

于 2011-10-01T01:49:09.157 に答える
1

ウィンドウズ

とを提供しCryptGenRandom()ますRtlGenRandom()。それらは、シードとして使用できるランダムなバイトの配列を提供します。

ドキュメントはmsdn ページにあります。

Linux / Unix

Openssl を使用RAND_bytes()して、Linux でランダムなバイト数を取得できます。デフォルトで使用/dev/randomします。

それを一緒に入れて:

#ifdef _WIN32
  #include <NTSecAPI.h>
#else
  #include <openssl/rand.h> 
#endif

uint32_t get_seed(void)
{
  uint32_t seed = 0;

#ifdef _WIN32
  RtlGenRandom(&seed, sizeof(uint32_t) );
#else
  RAND_bytes(&seed, sizeof(uint32_t) ); 
#endif

  return seed;
}

openssl はデフォルトで暗号的に安全な PRNG を提供するため、直接使用できることに注意してください。詳細はこちら

于 2012-04-22T17:42:58.740 に答える
1

ちょっとしたアイデア... GUID(16バイト)を生成し、その4バイトまたは8バイトのチャンク(シードの予想される幅に応じて)を合計して、整数のラップアラウンドを可能にします。結果をシードとして使用します。

GUID は通常、GUID を生成したコンピュータの特性 (MAC アドレスなど) をカプセル化するため、2 つの異なるマシンが最終的に同じランダム シーケンスを生成する可能性は低くなります。

これは明らかに移植性がありませんが、システムに適した API/ライブラリを見つけるのは難しくありません (たとえばUuidCreate、Win32 やuuid_generateLinux)。

于 2011-10-01T03:36:40.267 に答える
0

適度に POSIX っぽいシステムを使用していると仮定すると、clock_gettime. これにより、現在の時間がナノ秒単位で得られます。これは、すべての実用的な目的で、同じ値を 2 回取得することは不可能であることを意味します。(理論的には、悪い実装では解像度がはるかに低くなる可能性があります。たとえば、ミリ秒に 100 万を掛けるだけですが、Linux のような半分まともなシステムでさえ、実際のナノ秒の結果が得られます。)

于 2011-10-01T03:40:47.713 に答える
0

一意性が重要な場合は、各ノードが他のノードによって要求された ID を認識できるようにする必要があります。これは、「ID x を要求した人はいますか?」と尋ねるプロトコルで行うことができます。または、各ノードが他のノードに割り当てられていない ID を選択できるように事前に調整します。

(GUID はマシンの MAC を使用するため、「事前に手配する」カテゴリに分類されます。)

なんらかの合意がなければ、2 つのノードが同じ ID を使用する危険があります。

于 2011-10-01T09:52:04.357 に答える