
シェルスクリプトを使って次のことをしたいと思います。 (単純化のためにINPUTに同じデータを使用しています。実際の生活では、ループラベルjjに応じてデータが変更されます。)
#!/bin/sh
for jj in `seq 100`; do
cat INPUT.file >> OUTPUT.file
done
しかし、これはファイルを開閉する操作がループで行われるため、非常に非効率的です。 INPUT.fileが大きいと、このコードが非常に遅くなる可能性があります。それで、Cで事前に割り当てられた変数を作成するのと同じように、バッファを持つか生成する方法があるかどうか疑問に思います。
答え1
ありがとうスティーブン・チャジェラス回答「echoとcatの実行時になぜこんなに大きな違いがあるのですか?」、正解はムル一度だけ呼び出すとcat
改善することができます(ただし、データが大きくループの繰り返しが多い場合は、この「わずかな」量が増える可能性があります。私のシステムでは、このスクリプトはループスクリプトにかかる時間の約75%を占めます)。
#!/bin/sh
yes INPUT.file | head -100 | xargs cat >> OUTPUT.file
答え2
リダイレクトループ自体を考えてみましょう。
#!/bin/sh
for jj in seq 100; do
cat INPUT.file
done >> OUTPUT.file
答え3
速度が主な関心事である場合は、cat
この作業を十分に早く完了できないことがわかります。コンポーネントファイルを出力に並列に書き込むことができます。
cat
私は次の注意を払って並列高速バージョンを作成しました。
- すべての入力ファイルは通常のファイルでなければなりません(サイズを事前に知ることができます)。
fcat
実行中に入力ファイルを書き込んだり切ったりしないでください。- 出力ファイルは既に存在することはできません(驚きを防ぎ、すぐに対処する内容を読むのに時間を無駄にしないため)。
明らかに、これは迅速な概念証明であるため、より強力にすることができますが、アイデアは次のとおりです。
fcat.c:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
struct in_fd {
int fd;
int err;
off_t start;
struct stat s;
};
int main(int argc, char**argv)
{
char *outfile = argv[--argc];
if (argc < 2) {
fprintf(stderr, "Usage: %s INFILE... OUTFILE\n", argv[0]);
return 1;
}
struct in_fd *infiles = calloc(argc, sizeof *infiles);
#pragma omp parallel for
for (int i = 1; i < argc; ++i) {
struct in_fd *const input = infiles + i;
char const *const filename = argv[i];
input->err = 0;
if ((input->fd = open(filename, O_RDONLY)) < 0) {
perror(filename);
input->err = errno;
continue;
}
if (fstat(input->fd, &input->s)) {
perror(filename);
input->err = errno;
continue;
}
if (!S_ISREG(input->s.st_mode)) {
fprintf(stderr, "%s: not a regular file\n", filename);
input->err = EINVAL;
continue;
}
}
off_t total = 0;
for (int i = 1; i < argc; ++i) {
if (infiles[i].err)
return EXIT_FAILURE;
infiles[i].start = total;
total += infiles[i].s.st_size;
}
int out_fd = open(outfile, O_RDWR | O_CREAT | O_EXCL, 0666);
if (out_fd < 1) {
perror(outfile);
return 1;
}
if (ftruncate(out_fd, total)) {
perror(outfile);
return 1;
}
/* On Linux, you might wish to add MAP_HUGETLB */
char *out_mem = mmap(NULL, total, PROT_WRITE, MAP_SHARED, out_fd, 0);
if (out_mem == MAP_FAILED) {
perror(outfile);
return 1;
}
#pragma omp parallel for
for (int i = 1; i < argc; ++i) {
struct in_fd *const input = infiles + i;
char *p = out_mem + input->start;
char *end = p + input->s.st_size;
input->err = 0;
while (p < end) {
int r = read(input->fd, p, end-p);
if (r < 0) {
if (errno != EINTR) {
perror(argv[i]);
input->err = errno;
break;
}
} else {
p += r;
}
}
close(infiles->fd);
}
if (munmap(out_mem, total)) {
perror(outfile);
}
for (int i = 1; i < argc; ++i) {
if (infiles[i].err) {
unlink(outfile);
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
ファイル生成:
CFLAGS += -Wall -Wextra
CFLAGS += -std=c99 -D_GNU_SOURCE
CFLAGS += -g -O2
CFLAGS += -fopenmp
all: fcat
.PHONY:all
私の12スレッドの私のタイミングは、0.2秒のランタイムと2.3秒のランタイムを示しましたcat
(それぞれ3つの実行、ホットキャッシュの使用、48のファイル、合計138M)。