Bashスクリプトを試しましたが、単純な1 MBファイルを作成するには時間がかかりすぎました。答えは/dev/random
または/dev/urandom
を使用することにあると思いますが、ここの他の投稿では、これらのものを使用してすべての種類のデータをファイルに追加する方法のみを示していますが、数値のみを追加します。
それで、0から9までの数字のみを含むサイズ1 GBのランダムファイルを作成するために使用できるコマンドはありますか?
編集:私は出力をこのようなものにしたい
0 1 4 7 ..... 9
8 7 5 8 ..... 8
....
....
8 7 5 3 ..... 3
範囲は0〜9で、0、1、2、3、4、5、6、7、8、9の数字のみを意味します。また、スペースで区切って、1行あたり100まで、n
までにする必要があります。行数。このnは気にしないものです。最終サイズを1 GBにしたいと思います。
編集:私はUbuntu 16.04 LTSを使用しています
これは、質問のタイトルのため、部分的には口の内の答えです。
"...への最速の方法"を探す場合、答えはほとんどの場合特殊なツールです。この「答え」は、そのようなツールの1つを示しているので、実験することができます。
これは深刻な答えではありません。一度だけ、またはごくまれにしか実行しないジョブに特化したツールを調べてはならないからです。なるほど、実際に何かを行うよりも、ツールを探してそれらについて学ぶことに多くの時間を費やすことになります。 bash
やawk
のようなシェルやユーティリティは最速ではありませんが、通常は次のように記述できますワンライナーほんの数秒を費やして、仕事を達成します。 Perl
のようなより優れたスクリプト言語も使用できますが、Perl
の学習曲線は急であり、私はひどいPerlプロジェクトに悩まされてきたので、そのような目的にはお勧めしません。一方、python
は、I/Oがかなり遅いため、わずかに障害があります。ただし、ギガバイトのデータをフィルタリングまたは生成する場合にのみ問題になります。
いずれの場合でも、次のC89サンプルプログラム(POSIX.1を使用してより精度の高いクロックを使用できる場合のみ)は約100 MB/sの生成速度を達成する必要があります(Intel i5-4200Uプロセッサを搭載したラップトップ上のLinuxでテストし、出力をパイプします) _/dev/null
_)に、かなり良い疑似乱数ジェネレータを使用します。 (コードは xorshift64 * と除外メソッドを使用して桁の偏りを避けるため、出力はMatrixRankテストを除くすべてのBigCrunchテストに合格する必要があります。)
_#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <locale.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
/* This program is licensed under the CC0 license,
https://creativecommons.org/publicdomain/zero/1.0/
In other words, this is dedicated to the public domain.
There are no warranties either, so if something breaks,
you only have yourself to blame.
*/
#if _POSIX_C_SOURCE-199309 >= 0
static uint64_t time_seed(void)
{
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts))
return (uint64_t)time(NULL);
return (uint64_t)ts.tv_sec
^ (((uint64_t)ts.tv_nsec) << 32);
}
#else
static uint64_t time_seed(void)
{
return (uint64_t)time(NULL);
}
#endif
/* Preferred output I/O block size.
* Currently, about 128k blocks yield
* maximum I/O throughput on most devices.
* Note that this is a heuristic value,
* and may be increased in the future.
*/
#ifndef IO_BLOCK_SIZE
#define IO_BLOCK_SIZE 262144
#endif
/* This is the Xorshift* pseudo-random number generator.
* See https://en.wikipedia.org/wiki/Xorshift#xorshift.2A
* for details. This is an incredibly fast generator that
* passes all but the MatrixRank test of the BigCrush
* randomness test suite, with a period of 2^64-1.
* Note that neither xorshift_state, nor the result of
* this function, will ever be zero.
*/
static uint64_t xorshift_state;
static uint64_t xorshift_u64(void)
{
xorshift_state ^= xorshift_state >> 12;
xorshift_state ^= xorshift_state << 25;
xorshift_state ^= xorshift_state >> 27;
return xorshift_state * UINT64_C(2685821657736338717);
}
/* This function returns a number between (inclusive)
* 0 and 999,999,999,999,999,999 using xorshift_u64()
* above, using the exclusion method. Thus, there is
* no bias in the results, and each digit should be
* uniformly distributed in 0-9.
*/
static uint64_t quintillion(void)
{
uint64_t result;
do {
result = xorshift_u64() & UINT64_C(1152921504606846975);
} while (!result || result > UINT64_C(1000000000000000000));
return result - UINT64_C(1);
}
/* This function returns a single uniformly random digit.
*/
static unsigned char digit(void)
{
static uint64_t digits_cache = 0;
static unsigned char digits_cached = 0;
unsigned char retval;
if (!digits_cached) {
digits_cache = quintillion();
digits_cached = 17; /* We steal the first one! */
} else
digits_cached--;
retval = digits_cache % (uint64_t)(10);
digits_cache /= (uint64_t)(10);
return retval;
}
static int parse_ulong(const char *src, unsigned long *to)
{
const char *end = src;
unsigned long value;
if (!src)
return errno = EINVAL;
errno = 0;
value = strtoul(src, (char **)&end, 0);
if (errno)
return errno;
if (end == src)
return errno = EINVAL;
while (*end)
if (isspace(*end))
end++;
else
return errno = EINVAL;
if (to)
*to = value;
return 0;
}
int main(int argc, char *argv[])
{
unsigned long lines, cols, line, col, seed;
/* When parsing the command-line parameters,
* use locale conventions. */
setlocale(LC_ALL, "");
/* Standard output should be fully buffered, if possible.
* This only affects output speed, so we're not too worried
* if this happens to fail. */
(void)setvbuf(stdout, NULL, _IOFBF, (size_t)IO_BLOCK_SIZE);
if (argc < 3 || argc > 4 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s COLS LINES [ SEED ]\n", argv[0]);
fprintf(stderr, "\n");
fprintf(stderr, "This program generates random decimal digits\n");
fprintf(stderr, "0 - 9, separated by spaces, COLS per line,\n");
fprintf(stderr, "LINES lines. In total, COLS*LINES*2 bytes\n");
fprintf(stderr, "will be used.\n");
fprintf(stderr, "\n");
fprintf(stderr, "SEED is the optional seed for the Xorshift64*\n");
fprintf(stderr, "pseudo-random number generator used in this program.\n");
fprintf(stderr, "If omitted, current time is used as the seed.\n");
fprintf(stderr, "\n");
return EXIT_SUCCESS;
}
if (parse_ulong(argv[1], &cols) || cols < 1UL) {
fprintf(stderr, "%s: Invalid number of digits per line.\n", argv[1]);
return EXIT_FAILURE;
}
if (parse_ulong(argv[2], &lines) || lines < 1UL) {
fprintf(stderr, "%s: Invalid number of lines.\n", argv[2]);
return EXIT_FAILURE;
}
if (argc > 3) {
if (parse_ulong(argv[3], &seed)) {
fprintf(stderr, "%s: Invalid Xorshift64* seed.\n", argv[3]);
return EXIT_FAILURE;
}
} else
seed = time_seed();
/* Since zero seed is invalid, we map it to ~0. */
xorshift_state = seed;
if (!xorshift_state)
xorshift_state = ~(uint64_t)0;
/* Discard first 1000 values to make the initial values unpredictable. */
for (col = 0; col < 1000; col++)
xorshift_u64();
for (line = 0UL; line < lines; line++) {
fputc('0' + digit(), stdout);
for (col = 1UL; col < cols; col++) {
fputc(' ', stdout);
fputc('0' + digit(), stdout);
}
fputc('\n', stdout);
/* Check for write errors. */
if (ferror(stdout))
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
_
ラインバッファに切り替えると、より高速に処理でき、一度に各桁を出力する代わりに、fwrite()
を1回実行します。出力がブロックデバイスである場合、部分的な(2の累乗ではない)書き込みを回避するために、ストリームを完全にバッファリングしたままにすることに注意してください。
_#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <locale.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
#if _POSIX_C_SOURCE-199309 >= 0
static uint64_t time_seed(void)
{
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts))
return (uint64_t)time(NULL);
return (uint64_t)ts.tv_sec
^ (((uint64_t)ts.tv_nsec) << 32);
}
#else
static uint64_t time_seed(void)
{
return (uint64_t)time(NULL);
}
#endif
/* Preferred output I/O block size.
* Currently, about 128k blocks yield
* maximum I/O throughput on most devices.
* Note that this is a heuristic value,
* and may be increased in the future.
*/
#ifndef IO_BLOCK_SIZE
#define IO_BLOCK_SIZE 262144
#endif
/* This is the Xorshift* pseudo-random number generator.
* See https://en.wikipedia.org/wiki/Xorshift#xorshift.2A
* for details. This is an incredibly fast generator that
* passes all but the MatrixRank test of the BigCrush
* randomness test suite, with a period of 2^64-1.
* Note that neither xorshift_state, nor the result of
* this function, will ever be zero.
*/
static uint64_t xorshift_state;
static uint64_t xorshift_u64(void)
{
xorshift_state ^= xorshift_state >> 12;
xorshift_state ^= xorshift_state << 25;
xorshift_state ^= xorshift_state >> 27;
return xorshift_state * UINT64_C(2685821657736338717);
}
/* This function returns a number between (inclusive)
* 0 and 999,999,999,999,999,999 using xorshift_u64()
* above, using the exclusion method. Thus, there is
* no bias in the results, and each digit should be
* uniformly distributed in 0-9.
*/
static uint64_t quintillion(void)
{
uint64_t result;
do {
result = xorshift_u64() & UINT64_C(1152921504606846975);
} while (!result || result > UINT64_C(1000000000000000000));
return result - UINT64_C(1);
}
/* This function returns a single uniformly random digit.
*/
static unsigned char digit(void)
{
static uint64_t digits_cache = 0;
static unsigned char digits_cached = 0;
unsigned char retval;
if (!digits_cached) {
digits_cache = quintillion();
digits_cached = 17; /* We steal the first one! */
} else
digits_cached--;
retval = digits_cache % (uint64_t)(10);
digits_cache /= (uint64_t)(10);
return retval;
}
static int parse_ulong(const char *src, unsigned long *to)
{
const char *end = src;
unsigned long value;
if (!src)
return errno = EINVAL;
errno = 0;
value = strtoul(src, (char **)&end, 0);
if (errno)
return errno;
if (end == src)
return errno = EINVAL;
while (*end)
if (isspace(*end))
end++;
else
return errno = EINVAL;
if (to)
*to = value;
return 0;
}
int main(int argc, char *argv[])
{
unsigned long lines, cols, line, col, seed;
char *oneline;
/* When parsing the command-line parameters,
* use locale conventions. */
setlocale(LC_ALL, "");
/* Standard output should be fully buffered, if possible.
* This only affects output speed, so we're not too worried
* if this happens to fail. */
(void)setvbuf(stdout, NULL, _IOFBF, (size_t)IO_BLOCK_SIZE);
if (argc < 3 || argc > 4 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s COLS LINES [ SEED ]\n", argv[0]);
fprintf(stderr, "\n");
fprintf(stderr, "This program generates random decimal digits\n");
fprintf(stderr, "0 - 9, separated by spaces, COLS per line,\n");
fprintf(stderr, "LINES lines. In total, COLS*LINES*2 bytes\n");
fprintf(stderr, "will be used.\n");
fprintf(stderr, "\n");
fprintf(stderr, "SEED is the optional seed for the Xorshift64*\n");
fprintf(stderr, "pseudo-random number generator used in this program.\n");
fprintf(stderr, "If omitted, current time is used as the seed.\n");
fprintf(stderr, "\n");
return EXIT_SUCCESS;
}
if (parse_ulong(argv[1], &cols) || cols < 1UL) {
fprintf(stderr, "%s: Invalid number of digits per line.\n", argv[1]);
return EXIT_FAILURE;
}
if (parse_ulong(argv[2], &lines) || lines < 1UL) {
fprintf(stderr, "%s: Invalid number of lines.\n", argv[2]);
return EXIT_FAILURE;
}
if (argc > 3) {
if (parse_ulong(argv[3], &seed)) {
fprintf(stderr, "%s: Invalid Xorshift64* seed.\n", argv[3]);
return EXIT_FAILURE;
}
} else
seed = time_seed();
/* Since zero seed is invalid, we map it to ~0. */
xorshift_state = seed;
if (!xorshift_state)
xorshift_state = ~(uint64_t)0;
/* Discard first 1000 values to make the initial values unpredictable. */
for (col = 0; col < 1000; col++)
xorshift_u64();
/* Allocate memory for a full line. */
oneline = malloc((size_t)(2 * cols + 1));
if (!oneline) {
fprintf(stderr, "Not enough memory for %lu column buffer.\n", cols);
return EXIT_FAILURE;
}
/* Set spaces and terminating newline. */
for (col = 0; col < cols; col++)
oneline[2*col + 1] = ' ';
oneline[2*cols-1] = '\n';
/* Not needed, but in case a code modification treats it as a string. */
oneline[2*cols] = '\0';
for (line = 0UL; line < lines; line++) {
for (col = 0UL; col < cols; col++)
oneline[2*col] = digit();
if (fwrite(oneline, 2*cols, 1, stdout) != 1)
return EXIT_FAILURE;
}
/* Check for write errors. */
if (ferror(stdout))
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
_
注:2016-11-18で編集された両方の例はensure数字の均一な分布(ゼロは除外されます。例 こちら を参照)さまざまな疑似乱数ジェネレータの比較と詳細については)。
例を使用してコンパイル
_gcc -Wall -O2 decimal-digits.c -o decimal-digits
_
オプションで、システム全体に_/usr/bin
_を使用してインストールします
_Sudo install -o root -g root -m 0755 decimal-digits /usr/bin
_
1行あたりの桁数と行数が必要です。 _1000000000 / 100 / 2 = 5000000
_(500万;合計バイトを列で割って2で割る)なので、次のように使用できます。
_./decimal-digits 100 5000000 > digits.txt
_
oPの要求に応じて、ギガバイトサイズの_digits.txt
_を生成します。
プログラム自体は、効率よりも可読性を重視して記述されていることに注意してください。ここでの私の意図は、コードの効率性を示すことではなく、汎用のCインターフェイスではなく、POSIX.1と低レベルI/Oを使用することですが、費やした労力とのバランスの種類を簡単に確認できます専用ツールの開発とパフォーマンスの比較において、ワンライナーまたは短いシェルまたはawkスクリプトレットと比較して。
GNU Cライブラリを使用して、すべての文字出力に対してfputc()
関数を呼び出すと、(間接的な関数呼び出しまたは条件付き-FILE
インターフェースは実際にはかなり複雑で用途が広いと思います。この特定のIntel Core i5-4200Uラップトップでは、出力を_/dev/null
_にリダイレクトします。最初の(fputc)バージョンは約11秒かかりますが、 -a-timeバージョンは1.3秒しかかかりません。
たまたまそういうプログラムやジェネレーターを書くのは、巨大なデータセットで遊ぶのが好きだからです。私はそのように変です。たとえば、私はかつて、すべての有限の正のIEEE-754浮動小数点値をテキストファイルに出力するプログラムを書いたが、解析時に正確に同じ値を生成するのに十分な精度であった。ファイルのサイズは数ギガバイト(おそらく4G程度)でした。有限の肯定的なfloat
sはそれほど多くありません。これを使用して、そのようなデータを読み取って解析する実装を比較しました。
OPのような通常の使用例では、シェルスクリプトとスクリプトレット、ワンライナーがより良いアプローチです。タスク全体を完了するために費やされる時間が短縮されます。 (毎日別のファイルが必要な場合や、別のファイルを必要とする人がたくさんいる場合を除きます。まれに、上記のような専用のツールを使用すれば、労力を費やすことができます。)
この:
_ LC_ALL=C tr '\0-\377' \
'[0*25][1*25][2*25][3*25][4*25][5*25][6*25][7*25][8*25][9*25][x*]' \
< /dev/urandom |
tr -d x |
fold -w 1 |
paste -sd "$(printf '%99s\\n')" - |
head -c1G
_
(head
実装が_-c
_をサポートすることを前提としています)は、私のシステムではかなり高速に見えます。
tr
は、バイト範囲全体(0から255、8進数で0から0377)を変換します。最初の25バイトを0、次の25バイトを1、次に25 9残りを(250から255)に変換します。 "x"は(_tr -d x
_自体が均一分布であることを前提として)均一分布が必要なため、破棄し(_/dev/urandom
_を使用)、一部の桁にバイアスをかけません。
これにより、_/dev/urandom
_のバイトの97%に1桁が生成されます。 _fold -w 1
_は、1行あたり1桁にします。 _paste -s
_は、99のスペース文字と1つの改行文字で構成されるセパレーターのリストを使用して呼び出されるため、各行に100のスペースで区切られた数字があります。
_head -c1G
_は最初のGiB(230) その。最後の行は切り捨てられ、区切られないことに注意してください。あなたは2に切り捨てることができます30-1、不足している改行を手動で追加するか、10に切り捨てます9 代わりに、これらの200バイト行の5,000万バイト(_head -n 50000000
_も標準/ポータブルコマンドになります)。
これらのタイミング(クアッドコアシステムでzsh
によって取得)は、CPU時間の消費場所を示します。
_LC_ALL=C tr '\0-\377' < /dev/urandom 0.61s user 31.28s system 99% cpu 31.904 total
tr -d x 1.00s user 0.27s system 3% cpu 31.903 total
fold -w 1 14.93s user 0.48s system 48% cpu 31.902 total
paste -sd "$(printf '%99s\\n')" - 7.23s user 0.08s system 22% cpu 31.899 total
head -c1G > /dev/null 0.49s user 1.21s system 5% cpu 31.898 total
_
最初のtr
はボトルネックであり、ほとんどがカーネルで費やされた時間です(乱数の生成を想定しています)。タイミングは、_/dev/uramdom
_からバイトを取得できる速度とほぼ一致します(約19MiB /秒、ここでは、32MiB /秒の速度で/ dev/urandomの0.97バイトごとに2バイトを生成します)。 fold
は、各バイトの後に改行文字を挿入するためだけに不合理な量のCPU時間(15秒)を費やしているようですが、私の場合は別のCPUで動作するため、全体の時間には影響しません( _-b
_オプションを使用すると、効率がわずかに向上します。_dd cbs=1 conv=unblock
_は、より良い代替手段のようです)。
_head -c1G
_を廃止し、ファイルサイズに制限を設定することで数秒を節約できます(zsh
で_limit filesize 1024m
_または他のほとんどのシェルでulimit -f "$((1024*1024))"
) (zsh
を含む))代わりにサブシェルで。
バイトごとに2桁を抽出すれば改善できるかもしれませんが、そのためには別のアプローチが必要になります。 tr
は256バイト配列の各バイトを検索するだけなので、上記は非常に効率的です。一度に2バイトではこれを行うことはできません。より複雑なアルゴリズムを使用してバイトのテキスト表現を計算する_hexdump -e '1/1 "%02u"'
_などを使用すると、乱数の生成自体よりもコストが高くなります。それでも、私の場合のように、時間に余裕のあるCPUコアがある場合でも、数秒で削り落とすことができます。
と:
_< /dev/urandom LC_ALL=C tr '\0-\377' '\0-\143\0-\143[x*]' |
tr -d x |
hexdump -n250000000 -ve '500/1 "%02u" "\n"' |
fold -w1 |
paste -sd "$(printf '%99s\\n')" - > /dev/null
_
私は得ます(ただし、ここでは1,073,741,824ではなく1,000,000,000バイトです):
_LC_ALL=C tr '\0-\377' '\0-\143\0-\143[x*]' < /dev/urandom 0.32s user 18.83s system 70% cpu 27.001 total
tr -d x 2.17s user 0.09s system 8% cpu 27.000 total
hexdump -n250000000 -ve '500/1 "%02u" "\n"' 26.79s user 0.17s system 99% cpu 27.000 total
fold -w1 14.42s user 0.67s system 55% cpu 27.000 total
paste -sd "$(printf '%99s\\n')" - > /dev/null 8.00s user 0.23s system 30% cpu 26.998 total
_
全体的にはより多くのCPU時間ですが、私の4つのCPUコア間でより適切に分散されているため、実際にかかる時間は少なくなっています。現在、ボトルネックはhexdump
です。
行ベースのdd
の代わりにfold
を使用すると、実際にhexdump
が実行する必要がある作業量を削減し、CPU間の作業のバランスを改善できます。
_< /dev/urandom LC_ALL=C tr '\0-\377' '\0-\143\0-\143[x*]' |
tr -d x |
hexdump -ve '"%02u"' |
dd bs=50000 count=10000 iflag=fullblock status=none cbs=1 conv=unblock |
paste -sd "$(printf '%99s\\n')" -
_
(ここでは、GNU dd
をその_iflag=fullblock
_および_status=none
_に対して想定))とすると、次のようになります。
_LC_ALL=C tr '\0-\377' '\0-\143\0-\143[x*]' < /dev/urandom 0.32s user 15.58s system 99% cpu 15.915 total
tr -d x 1.62s user 0.16s system 11% cpu 15.914 total
hexdump -ve '"%02u"' 10.90s user 0.32s system 70% cpu 15.911 total
dd bs=50000 count=10000 iflag=fullblock status=none cbs=1 conv=unblock 5.44s user 0.19s system 35% cpu 15.909 total
paste -sd "$(printf '%99s\\n')" - > /dev/null 5.50s user 0.30s system 36% cpu 15.905 total
_
ボトルネックとなっている乱数生成に戻ります。
@OleTangeで指摘されているように、openssl
ユーティリティを使用している場合は、それを使用してバイトの高速ランダムジェネレーター(特にAES命令を持つプロセッサー)を取得できます。
_</dev/zero openssl enc -aes-128-ctr -nosalt -pass file:/dev/urandom
_
私のシステムでは、_/dev/urandom
_の1秒あたりのバイト数が15倍です。 (それが暗号的に安全なランダム性のソースの点で比較する方法についてコメントすることはできません).
_</dev/zero openssl enc -aes-128-ctr -nosalt -pass file:/dev/urandom 2> /dev/null |
LC_ALL=C tr '\0-\377' '\0-\143\0-\143[x*]' |
tr -d x |
hexdump -ve '"%02u"' |
dd bs=50000 count=10000 iflag=fullblock status=none cbs=1 conv=unblock |
paste -sd "$(printf '%99s\\n')" -
_
今与える:
_openssl enc -aes-128-ctr -nosalt -pass file:/dev/urandom < /dev/zero 2> 1.13s user 0.16s system 12% cpu 10.174 total
LC_ALL=C tr '\0-\377' '\0-\143\0-\143[x*]' 0.56s user 0.20s system 7% cpu 10.173 total
tr -d x 2.50s user 0.10s system 25% cpu 10.172 total
hexdump -ve '"%02u"' 9.96s user 0.19s system 99% cpu 10.172 total
dd bs=50000 count=10000 iflag=fullblock status=none cbs=1 conv=unblock 4.38s user 0.20s system 45% cpu 10.171 total
paste -sd "$(printf '%99s\\n')" - > /dev/null
_
ボトルネックとなっているhexdump
に戻ります。
まだCPUに余裕があるので、これらのhexdump
のうち3つを並行して実行できます。
_</dev/zero openssl enc -aes-128-ctr -nosalt -pass file:/dev/urandom 2> /dev/null |
LC_ALL=C tr '\0-\377' '\0-\143\0-\143[x*]' |
tr -d x |
(hexdump -ve '"%02u"' <&3 & hexdump -ve '"%02u"' <&3 & hexdump -ve '"%02u"') 3<&0 |
dd bs=50000 count=10000 iflag=fullblock status=none cbs=1 conv=unblock |
paste -sd "$(printf '%99s\\n')" -
_
(_<&3
_は、バックグラウンドで実行されたときに/ dev/nullでコマンドの標準入力を閉じるzsh
以外のシェルに必要です)。
これで6.2秒に短縮され、CPUがほぼ完全に使用されます。
shuf
が利用できる場合(最近GNU coreutilsが行う))、これを行うことができます:
time shuf -r -n $((512*1024*1024)) -i 0-9 | paste -sd "$(printf '%99s\\n')" -
私のVMでは、これはステファンの回答よりも約3:4だけ少し遅くなっています。
これが私が理解するのが簡単であることを望んでいる解決策です:
od -An -x /dev/urandom | tr -dc 0-9 | fold -w100 | awk NF=NF FS= | head -c1G
od
は、/dev/random
から16進数の均一なストリームを作成します。tr
は文字を取り除き、0-9
桁のみを保持しますfold
は、1行あたり100桁であることを保証しますawk
は行内にスペースを挿入しますhead
は入力を1ギガバイトに切り捨てますこれにはjot
コマンドを使用できます。
jot -r 50000000 0 9 | fmt -w 200 > output.txt
これはStéphaneChazelasの方法に似ていますが、パフォーマンスを向上させるために64ビットを一度に読み取りました。分布は依然として均一ですが、以前のように最良のケースでは8桁だけではなく、8バイトごとに19桁が得られます。
Perl -nle 'BEGIN{$/=\8; $,=" "}
$n = unpack("Q");
next if $n >= 10000000000000000000;
$s = sprintf("%019u", $n);
Push @a, (split //, $s);
if (@a >= 100) {print (splice @a, 0, 100);}' < /dev/urandom | head -c1G
32ビットプラットフォームでは、19ではなく9桁が毎回読み取られます。
スピードが必要な場合は、コンパイルされたプログラミング言語を使用する際にNominal Animalに同意します。ただし、Cで独自のRNGコードを記述する必要はありません。C++ 11は、標準ライブラリの一部として優れたMersenne Twisterを提供しています。
#include <time.h>
#include <random>
#include <iostream>
using namespace std;
int main() {
mt19937 gen(time(0));
uniform_int_distribution<> dist(0,9);
for(int j=0; j<5000000; j++){
for (int i = 0; i < 99; i++) {
cout << dist(gen) << " ";
}
cout << dist(gen) << endl;
}
return 0;
}
上記のコードはかなりシンプルで、出力をファイルにパイプするときに約1分かかります。 100桁の十分な大きさの文字列を作成し、その桁にハッキングすることで、はるかに速く処理できます。これにより、coutをすべての数字ではなくすべての行に呼び出すことができます。
#include <time.h>
#include <random>
#include <iostream>
using namespace std;
int main() {
mt19937 gen(time(0));
uniform_int_distribution<> dist(0,9);
char line[201];
for(int i=1; i<199; i++)
line[i] = ' ';
line[199] = '\n';
line[200] = 0;
for(int j=0; j<5000000; j++){
for (int i = 0; i < 199; i += 2) {
line[i] = dist(gen)+'0';
}
cout << line;
}
return 0;
}
このコードは私のマシンに約6秒かかります。これは標準出力であることを忘れないでください。そのため、ファイルにパイプしてください。
免責事項がいくつかあります。まず、これをWindows PCで書いています。ライブラリはすべてLinuxに存在すると思いますが、私が間違っている場合は、必ず指摘してください。
また、実際には、正確に5億の空白で区切られた数字を出力します。これは、技術的にはギガバイトですが、望んだとおりではない場合があります。 500万行、1行あたり100桁を出力します。違いが重要な場合は、行数を増やすことができます。私のWindowsボックスでは、ファイルは10 ^ 9バイトより少し大きいようですが、これは余分な改行文字と関係があると思います。
「ランダム」の定義に依存します。暗号的にランダムな場合は、優れたライブラリを入手して弾丸を噛み、実行されるまで待つ必要があります。
かなりランダムに見えるものが必要な場合は、簡単な方法を次に示します。
遅いマシンで実行するには1時間かかる場合があります。ほとんどの目的に十分な速度と十分なランダム性。
#!/bin/bash
FILE_CREAT='/tmp/testfile'
MAX_SIZE=$(( 1 * 1024 * 1024 ))
rm -rf ${FILE_CREAT}
while true
do
STRING=''
for (( i = 0 ; i < 100 ; i++ ))
do
NUM_RAN=$(cat /dev/urandom | tr -dc 0-9 | head -c 1)
if [ $i -eq 0 ]
then
STRING=${NUM_RAN}
else
STRING=${STRING}' '${NUM_RAN}
fi
done
echo ${STRING} >> $FILE_CREAT
FILE_SIZE=$(du -s ${FILE_CREAT} | awk '{print $1}')
if [ ${FILE_SIZE} -ge ${MAX_SIZE} ]
then
break
fi
done
exit $1