【问题标题】:Is there any faster way to truncate column in Unix有没有更快的方法来截断 Unix 中的列
【发布时间】:2012-12-22 22:52:18
【问题描述】:

我想在 Unix 中将 TSV 文件的第 4 列截断为给定长度。文件有几百万条记录,大小为 8GB。

我正在尝试这个,但它似乎有点慢。

awk -F"\t" '{s=substr($4,0,256); print $1"\t"$2"\t"$3"\t"s"\t"$5"\t"$6"\t"$7}' file > newFile

有没有更快的替代品?

谢谢

【问题讨论】:

  • 现在有多快?你想要多快?没有数字就无法有意义地谈论性能。

标签: unix


【解决方案1】:

您的命令可以写得更好一些(假设您正在重新构建记录),这可能会提高一些性能:

awk 'BEGIN { FS=OFS="\t" } { $4 = substr($4,0,256) }' file > newFile

如果您可以访问多核机器(您可能会这样做),则可以使用GNU parallel。你可能想要改变你使用的核心数量(我在这里设置了 4 个)和提供给 awk 的块大小(我已经设置为 2 MB)...

< file parallel -j 4 --pipe --block 2M -q awk 'BEGIN { FS=OFS="\t" } { $4 = substr($4,0,2) }' > newFile


以下是我在我的系统上使用 2.7G 文件进行的一些测试,该文件有 1 亿行,块大小为 2M:

time awk 'BEGIN { FS=OFS="\t" } { $4 = substr($4,0,2) }' file >/dev/null

结果:

real    1m59.313s
user    1m57.120s
sys     0m2.190s

单核:

time < file parallel -j 1 --pipe --block 2M -q awk 'BEGIN { FS=OFS="\t" } { $4 = substr($4,0,2) }' >/dev/null

结果:

real    2m28.270s
user    4m3.070s
sys     0m41.560s

四核:

time < file parallel -j 4 --pipe --block 2M -q awk 'BEGIN { FS=OFS="\t" } { $4 = substr($4,0,2) }' >/dev/null

结果:

real    0m54.329s
user    2m41.550s
sys     0m31.460s

十二核:

time < file parallel -j 12 --pipe --block 2M -q awk 'BEGIN { FS=OFS="\t" } { $4 = substr($4,0,2) }' >/dev/null

结果:

real    0m36.581s
user    2m24.370s
sys     0m32.230s

【讨论】:

  • 非常感谢这些研究工作。我并不是要在几秒钟内比较所有方法的性能。我问这个问题只是为了确保我的方法不是超级低效。
【解决方案2】:

我假设您的文件在字段之间只有一个空格字符,并且在行首没有空格。如果这是错误的,则可以对其进行增强。 否则,这应该可以工作:

sed 's/^\([^ ]* [^ ]* [^ ]* [^ ]\{1,256\}\)[^ ]* /\1 /'

我实际上并没有使用 256 个字符长的数据对其进行测试(我使用 \{1,2\} 对其进行了测试,但我不知道它的速度与 awk 相比如何。顺便说一句,在某些版本上,您可能需要去掉花括号中的反斜杠,只使用{1,256}

【讨论】:

    【解决方案3】:

    如果 Scott 或 Steve 的解决方案仍然太慢,可能是时候打破 C。运行为 ./a.out &lt; file &gt; newFile。首先测试一个带有一些长字段的小文件;我不是 100% 确定我的数学是正确的。

    #include <stdio.h>
    int
    main(void)
    {
        int field = 1;
        int character = 0;
        int c;
        while ((c = getchar()) != EOF)
        {
            switch (c)
            {
            case '\n':
                field = 1;
                character = 0;
                break;
            case '\t':
                character = 0;
                field++;
                break;
            default:
                character++;
                break;
            }
            if (field != 4 || character < 256)
                putchar(c);
        }
        if (ferror(stdout) || fflush(stdout) || fclose(stdout))
        {
            perror("write");
            return 1;
        }
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-02
      • 2018-12-12
      • 2016-02-06
      • 2011-03-22
      • 1970-01-01
      相关资源
      最近更新 更多