awk性能和CPU运行时间



我有一个包含数百万行和数千列/字段的输入文件。有人能向我解释一下,为什么下面两个产生相同输出的awk方法在CPU运行时间方面差异如此之大吗?

175.0秒:

awk 'BEGIN{FS=":| "}NR>1{field1=$1;field2=$2;$1="";$2="";print field1":"field2,field1":"field2,field2,$0}' file_in > file_out

19.7秒:

cat file_in | awk 'BEGIN{FS=":"}NR>1{print $1,$2}' | awk '{print $1":"$2,$1":"$2,$0}' | cut -d " " -f 3 --complement > file_out

这是一个只有数百列/字段的file_in的第2行和第3行(行与行之间没有换行符):

1:1000071 C T 1 0 0 1 0 0
1:1000759 C T 1 0 0 0 1 0

以下是file_out的相应行:

1:1000071 1:1000071 1000071 C T 1 0 0 1 0 0
1:1000759 1:1000759 1000759 C T 1 0 0 0 1 0

这两条语句:

$1="";$2=""

导致awk对每条记录重新编译两次。考虑到数百万行和数千个字段,我预计这将产生影响。

如果您向我们展示几行具有代表性的样本输入和预期输出,我们可以向您展示如何简洁高效地完成这项工作。

看起来你所做的就是转换这样的行:

1:1000071 C T 1 0 ...
1:1000759 C T 1 0 ...

到这样的线路:

1:1000071 1:1000071 1000071 C T 1 0 ...
1:1000759 1:1000759 1000759 C T 1 0 ...

如果是这样,你所需要做的就是:

awk '{x=$1; sub(/[^:]+:/,x" "x" ")}1' file

或者,由于这是一个简单的单行替换,即使是sed也可以处理它:

sed 's/([^:]*:)([^ ]*)/12 12 2/' file

外观:

$ cat file
1:1000071 C T 1 0 ...
1:1000759 C T 1 0 ...
$ awk '{x=$1; sub(/[^:]+:/,x" "x" ")}1' file
1:1000071 1:1000071 1000071 C T 1 0 ...
1:1000759 1:1000759 1000759 C T 1 0 ...
$ sed 's/([^:]*:)([^ ]*)/12 12 2/' file
1:1000071 1:1000071 1000071 C T 1 0 ...
1:1000759 1:1000759 1000759 C T 1 0 ...

啊,但我看到你提到你的样本输入是从第2行开始的,所以我想你有一个标题行或其他东西可以跳过。那就是:

awk 'NR>1{x=$1; sub(/[^:]+:/,x" "x" ");print}' file
sed -n '2,$s/([^:]*:)([^ ]*)/12 12 2/p' file

最后,这里有一个替代的awk解决方案,如果你的行都以"1:"开头,它可能会更有效,如你的示例输入所示:

awk 'NR>1{print $1, $1, substr($0,3)}' file

这仍然是最快的解决方案:

  cat file_in | awk 'BEGIN{FS=":"}NR>1{print $1,$2}' | awk '{print $1":"$2,$1":"$2,$0}' | cut -d " " -f 3 --complement > file_out

最新更新