Awk跳过字段分离以获得更高的速度



我有一个相当大的数据集(10K个文件,每个文件有20K行)。我需要交换文件和行(给自己20K个文件,每个文件有10K行)。

我有一个解决方案,将所有内容组合成一个巨大的表格,然后用cut提取列。。但是剪切花费的时间太长(扫描4GB文件10K次并不是很快,即使文件位于缓存中)。

因此,我在awk中写了一篇(非常简单)的文章:

awk '{ print >> "times/"FNR".txt" }' posns/*

这可以完成任务,但速度也相当慢(每个输入文件大约10秒)。我的猜测是,它正在进行场分离,尽管事实上我根本不需要。有没有办法禁用该功能以加快速度,或者我必须用另一种语言编写解决方案?

如果有帮助的话,虽然我更喜欢通用的解决方案,但每个文件中的每一行的形式都是%d %lf %lf,因此在这种情况下,行最多为21个字节(浮点值都小于100,整数为0或1)。

您可以尝试不同的awk。我听说mawk比其他awk快,GNu awk有一些性能改进,这意味着它可能比你使用的任何东西运行得更快。如果你将字段分隔符设置为记录分隔符,那么每行只有一个字段,所以如果你认为字段分割是个问题,那么这可能会加快速度。此外,您使用了错误的重定向运算符-您应该使用">"而不是">>",并且字符串串联很慢,所以我建议只打印到编号的文件,然后再全部重命名。

类似这样的东西:

cd times
awk -F'n' '{ print > FNR }' ../posns/*
for f in *
do
mv -- "$f" "${f}.txt"
done
cd ..

您可能想先在虚拟目录上测试它。

在这个线程中写入其他注释,可能会同时打开这么多文件,这就是问题所在,你能根据文件名中的一些模式对子组执行此操作吗?例如,如果您的posns文件都以数字开头:

cd times
rm -f *
for ((i=0; i<=9; i++))
do
awk -F'n' '{ print >> FNR }' ../posns/"$i"*
for f in *
do
mv -- "$f" "${f}.txt"
done
done
cd ..

请注意,在这种情况下,您需要首先清除输出文件。我相信有比这更好的方法来分组你的文件,但你需要告诉我们是否有命名约定。

我不知道这是否比awk快,但这里有一个perl脚本可以完成任务:

#!/usr/bin/perl
use strict;
use warnings;
my $line=0;
foreach(@ARGV){
open (MYINFILE, $_);
$line=0;
while(<MYINFILE>){
$line++;
open (MYOUTFILE,">>times/$line.txt");
print MYOUTFILE $_;
close (MYOUTFILE);
}
}

这听起来是拆分的完美工作;)

find posns -type f -exec split -l 10000 {} ;

可以使用-a-d选项自定义结果文件后缀。

解释:

  • find posns -type f:查找目录posns中的所有文件(递归)
  • -exec ... ;:对于找到的每个结果,执行以下命令...
  • split -l 10000 {}:当与-exec一起使用时,{}正是find的结果被替换到的地方。CCD_ 11将输入文件拆分为每个最多10k行的块

最终我放弃了漂亮的shell方法,并用C编写了另一个版本。这很可悲,它不漂亮,但它快了三个数量级以上(总运行时间为43秒,而awk方法在给定预缓存数据的情况下估计需要28小时)。它需要更改ulimit以允许打开足够多的文件,如果您的行比LINE_LENGTH长,它将无法正常工作。

尽管如此,它的运行速度还是次佳解决方案的2300倍。

如果有人在做这项任务时偶然发现了这一点,这就可以了。只要小心并检查它是否真的有效。

#include <stdio.h>
#include <stdlib.h>
#define LINE_LENGTH 1024
int main(int argc, char* argv[]) {
int fn;
int ln;
char read[LINE_LENGTH];
int fmax=10;
int ftot=0;
FILE** files=malloc(fmax*sizeof(FILE*));
char fname[255];
printf("%d argumentsn", argc);
printf("opening %sn",argv[1]);
FILE* open = fopen(argv[1],"r");
for(ln=0;fgets(read,LINE_LENGTH,open); ln++) {
if(ln==fmax) {
printf("%d has reached %d; reallocingn",ln,fmax);
fmax*=2;
files=realloc(files,fmax*sizeof(FILE*));
}
sprintf(fname, "times/%09d.txt",ln);
files[ln]=fopen(fname,"w");
if(files[ln]==0) {
fprintf(stderr,"Failed at opening file number %dn",ln);
return 1;
}
fprintf(files[ln],"%s",read);
}
ftot=ln;
fclose(open);
for(fn=2;fn<argc;fn++) {
printf("working on file %dn",fn);
open=fopen(argv[fn],"r");
for(ln=0;fgets(read,LINE_LENGTH,open); ln++) {
fprintf(files[ln],"%s",read);
}
fclose(open);
}
for(ln=0;ln<ftot;ln++) {
fclose(files[ln]);
}
return 0;
}

相关内容

  • 没有找到相关文章

最新更新