ほぼ10億の一意の整数レコードを生成する必要があります。私はawkを試しましたが、500万以上のレコードが生成されませんでした。私が今まで試したことは次のとおりです。
awk -v loop=10000000000 -v range=10000000000 'BEGIN{
srand()
do {
numb = 1 + int(rand() * range)
if (!(numb in prev)) {
print numb
prev[numb] = 1
count++
}
} while (count<loop)
}'
ただし、599160237以上のレコードが生成されなかったため、プロセスは自動的に終了しました。
答え1
GNU seq
+を使用sort
して、最初に一意の1B整数リスト(順番に)を作成してからランダムに混在させるsort -R
ことができます。これはCPU効率的ではありませんが、ソート時に使用可能なメモリを最大限に使用してから一時ファイルに戻すため、メモリに依存しません。
これは数分かかります(マシンのCPU / Ram /ディスクによって異なります)。
$ seq 1000000000 > 1B.txt
$ ls -lhog 1B.txt
-rw-rw-r-- 1 9.3G Dec 26 17:31 1B.txt
$ sort -R 1B.txt > 1B.random.txt
RAMが十分なコンピュータにアクセスできる場合は、GNUを使用できますshuf
。
$ shuf -i 1-1000000000 > 1B.random.txt
経験上shuf
、私のコンピュータには約8GBの空きメモリと約6分のランタイムが必要です。
答え2
タスクを完了するためにあまりにも多くのメモリを割り当てないプログラムを使用することをお勧めします。しかし、乱数生成に問題があります。完全に乱数が必要な場合は、/dev/urandomなどの「良い」乱数ソースを使用する必要があります。
私の考えではこのCプログラムこれを助けることができます。これは、ユーザーが指定する3つの引数(start int、end int、および生成する数値)を使用して実行時に数値を生成します。したがって、(0..200)の範囲で100個の整数を生成するには、次のようにします。
./mkrnd 0 200 100
ファイルにリダイレクトする必要がある場合は、次の手順を実行します。
./mkrnd 0 200 100 >randomints.txt
コンパイルはとても簡単です。ちょうどやってくださいgcc mkrnd.c -o mkrnd
(または私がコンパイルすることができます)。
十分速いと思いますが、作業にはまだ数時間かかります。 Athlon64 5000+の私の場合:
% time null ./mkrnd 0 1000000000 10000000
real 0m33.471s
user 0m0.000s
sys 0m0.000s
#if 0 ... #endifを削除して、/dev/urandomから任意の整数を取得します(遅くなる可能性があります)。
メモリー要件 関連: musl システムでは、ランタイム全体に 4K RSS のみが必要です。
編集する:gettimeofdayをclock_gettimeに置き換えると、速度が倍増します。
答え3
Python3.4では、次のように巨大な数字を生成して使用できます。
#!/bin/python3.4
import random
print(random.sample(range(1, 1000000000000),1000000000))
これにより、10億個の固有数字が印刷されます。
大規模なサンプルの割り当てにメモリの問題がある場合は、範囲を使用してループから数字を印刷できますが、これはランダムではないシーケンスです。
x=range(1, 1000000000000)
for i in x:
print (i) #or process i , whatever the operation is.
答え4
プロセスが終了する理由は、awk
コード内に発生した配列にバグ/制限があるか、またはコードが余分なスペースを使い果たして、一部のプロセスベースの制限に達するためです。
range
私の言葉は、定義された10億の値を含む最大インデックスが100億(基準)の配列を構築しようとしているということです。したがって、awk
100億個の変数のスペースを予約する必要があるかもしれません。これがどれくらいのスペースを意味するのかよく分からないが、100億個の16ビット整数は18.5GBを意味し、このような稀なawk
配列を構築するのが賢明であっても1.8GB以上が必要なので数字を保存することは生成。
結果を一意に保つには、以前の値をすべてどこかに保存する必要があるため、スペースを大幅に占めるしかありませんが、他の言語でアルゴリズムを実行することもできます。
それでは、膨大なメモリ要件をどのように削除できますか?
A.Gordonは、シーケンスに依存し、ランダム性を得るためにそれらを混合するオプションを提案しました。このアプローチは、結果が実際に数値でなければならず、その結果が指定された範囲から出るようにしたい場合にうまく機能します。範囲が1からNよりも複雑な場合は、生成シーケンスを使用してawk
から渡すことができますsort -R
。生成された数値の範囲と数を異なる方法にする方法に関する答えについての私のコメントもご覧ください。
1つのオプションは、暗号化(ハッシュ)関数を使用して乱数を生成することですが、この場合、これらの関数は通常Nビット出力を生成して結果を損なうことができないため、範囲を1からNに定義することはできません。衝突の危険はありません(セットに重複した数字があります)。しかし、これらの関数は簡単に10億のユニークな出力を生成することが保証されています(このハッシュ関数は非常に多くの反復呼び出しにもかかわらず同じ出力を2回生成しないように設計されているため)。実装によっては、出力が数値ではなく文字列である場合もあり、文字列出力を数値に変換することもできますが、通常は出力サイズが非常に大きいため、変換によって発生する数値の範囲も膨大です。から始めることができますこのStackoverflowの質問このオプションを見ることに興味があるなら。
衝突の危険がある場合は、可能性が低い場合でも、良いランダムソース(/ dev / urandomはオプション)を使用して10億の数字を生成できます。何十億ものユニークな数字を得る確率がどれくらいになるかはわかりませんが、試してみる価値は確かにあります。ただし、結果セットに重複項目があるかどうかを知るためのメモリ効率的な方法はありません。これを行うには、比較のためにすべての数値をメモリに保存する必要があるためです。