이것은 질문의 제목 때문에 부분적으로 뺨에 답입니다.
"가장 빠른 방법 ..." 을 찾으면 거의 항상 전문화 된 도구가됩니다. 이 "답변"에는 그러한 도구 중 하나가 표시되어 실험 할 수 있습니다.
한 번만 또는 매우 드물게 수행하는 작업을위한 특수 도구를 조사해서는 안되므로 이것은 심각한 대답이 아닙니다. 실제로 작업을 수행하는 것보다 도구를 찾고 도구에 대해 배우는 데 더 많은 시간을 소비하게됩니다. 쉘과 같은 유틸리티 bash
와는 awk
가장 빠른 아니지만, 당신은 일반적으로 쓸 수있는 한 라이너를 몇 초 지출, 작업을 달성하기 위해. perl
학습 곡선 perl
이 가파르 지만 더 나은 스크립팅 언어도 사용할 수 있습니다 . python
반면에 다소 느린 I / O로 인해 약간의 장애가 있습니다. 그러나 기가 바이트의 데이터를 필터링하거나 생성 할 때만 문제가됩니다.
어쨌든 다음 C89 예제 프로그램 (사용 가능한 경우에만보다 높은 정확도의 클럭에 POSIX.1을 사용함)은 약 100MB / s의 생성 속도를 달성해야합니다 (Linux에서 Intel i5-4200U 프로세서가 장착 된 랩톱에서 테스트 됨). 에 /dev/null
) 꽤 좋은 의사 난수 생성기를 사용하여. (코드는 xorshift64 * 및 배제 방법을 사용하여 숫자 바이어스를 피 하므로 MatrixRank 테스트를 제외한 모든 BigCrunch 테스트를 통과해야합니다 .)
10 진수 .c :
#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()
하면 한 번에 각 숫자를 출력하는 대신 한 번만 더 빠르게 만들 수 있습니다 . 출력이 블록 장치 인 경우 부분 (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에 편집되어 숫자의 균일 한 분포 를 보장합니다 (0은 제외됩니다. 예를 들어 다양한 의사 난수 생성기에 대한 비교 및 세부 사항은 여기 참조 ).
예를 들어 컴파일
gcc -Wall -O2 decimal-digits.c -o decimal-digits
선택적으로 /usr/bin
사용 하기 위해 시스템 전체에 설치
sudo install -o root -g root -m 0755 decimal-digits /usr/bin
행당 자릿수와 행 수를 사용합니다. 때문에 1000000000 / 100 / 2 = 5000000
(오백 만 2로 나눈 열로 나누어 총 바이트), 당신은 사용할 수 있습니다
./decimal-digits 100 5000000 > digits.txt
digits.txt
OP가 원하는대로 기가 바이트 크기를 생성합니다 .
프로그램 자체는 효율성을 염두에두고 읽기 편하게 작성되었습니다. 필자의 의도는 일반적인 C 인터페이스 대신 POSIX.1 및 저수준 I / O를 사용하는 코드의 효율성을 보여 주려는 것이 아니라 노력과 함께 어떤 종류의 균형이 있는지 쉽게 확인할 수 있도록하는 것입니다. 한 줄짜리 또는 짧은 쉘 또는 awk 스크립틀릿과 비교하여 전용 도구 개발과 성능 비교.
GNU C 라이브러리를 사용하면 fputc()
모든 문자 출력에 대해 함수를 호출하면 (간접 함수 호출 또는 조건부) 매우 작은 오버 헤드가 발생합니다. FILE
인터페이스는 실제로 매우 복잡하고 다재다능합니다. 이 특정 Intel Core i5-4200U 랩톱에서 출력을로 리디렉션하면 /dev/null
첫 번째 (fputc) 버전은 약 11 초가 걸리지 만 한 번에 한 줄 버전은 1.3 초 밖에 걸리지 않습니다.
나는 종종 거대한 데이터 세트를 가지고 노는 것을 좋아하기 때문에 그러한 프로그램과 생성기를 자주 작성합니다. 나는 그렇게 이상하다. 예를 들어, 나는 모든 유한 양의 IEEE-754 부동 소수점 값을 텍스트 파일로 인쇄하는 프로그램을 작성하여 구문 분석 할 때 정확히 동일한 값을 산출하기에 충분한 정밀도를 가졌습니다. 파일 크기는 몇 기가 바이트 (4G 정도 정도)였습니다. float
생각할 수 있듯이 유한 한 긍정적 인 것이 많지 않습니다 . 나는 이것을 사용하여 그러한 데이터를 읽고 구문 분석하는 구현을 비교했습니다.
OP와 같은 일반적인 사용 사례의 경우 셸 스크립트와 스크립틀릿과 한 줄짜리가 더 나은 방법입니다. 전체 작업을 수행하는 데 소요되는 시간이 줄어 듭니다. (매일 다른 파일을 필요로하거나 다른 파일을 필요로하는 사람들이 많을 경우를 제외하고는 위와 같은 전용 도구 인 드문 경우지만 보전 노력이 필요할 수 있습니다.)