我有一个awk脚本,通常使用外部变量$a并行运行。
awk -v a=$a '$4>a-5 && $4<a+5 {print $10,$4}' INFILE 当然,使用数组会运行得更快,所以我尝试这样做,让它做同样的事情(在LISTFILE中的$2是INFILE中$4的搜索值。
awk 'FNR==NR{a[$2]=($2-5);next}$4 in a{if ($4>a[$4] && $4<a[$4]+10 {print} LISTFILE INFILE当然,这不起作用,因为awk扫描到键,然后开始测试if语句,因此只找到下游范围。不幸的是,这不是一个连续的列表,所以通常没有$2-5值,否则我会使用它作为数组的关键。
显然,我知道如何使用awk和bash的组合来实现这一点,但是我想知道是否有一个awk唯一的解决方案。
发布于 2014-06-14 02:17:00
我的第一个答案回答了实际的问题,并修复了awk脚本。但也许我没有抓住重点。如果您想要速度,并且不介意更多地使用您的多核处理器,您可以使用GNU并行。下面是一个实现,它将同时启动4个作业:
awk_cmd='$4 > var - 5 && $4 < var + 5 { print $10, $4 }'
parallel -j 4 "awk -v var={} '$awk_cmd' INFILE" :::: LISTFILE正如您所看到的,这将最多同时读取INFILE四次。这个答案,在调整了作业数量之后,应该提供与您使用shell描述的并行实现非常相似的性能。因此,您可能希望将LISTFILE拆分为较小的块,并将awk_cmd设置为我在前面的答复中发布的命令。可能有一种处理输入的最佳方法,但这在很大程度上取决于INFILE的大小和LISTFILE中元素的数量。HTH。
测试:
创建LISTFILE
paste - - < <(seq 16) > LISTFILE创建INFILE
awk 'BEGIN { for (i=1; i<=9999999; i++) { print i, i, i, int(i * rand()), i, i, i, i, i, i } }' > INFILE结果:
TEST1:
time awk 'FNR==NR { a[$2]; next } { for (i in a) { if ($4 > i - 5 && $4 < i + 5) { print $10, $4 } } }' LISTFILE INFILE >/dev/null
real 0m45.198s
user 0m45.090s
sys 0m0.160sTEST2:
time for i in $(seq 1 2 16); do awk -v var="$i" '$4 > var - 5 && $4 < var + 5 { print $10, $4 }' INFILE; done >/dev/null
real 0m55.335s
user 0m54.433s
sys 0m0.953sTEST3:
awk_cmd='$4 > var - 5 && $4 < var + 5 { print $10, $4 }'
time parallel --colsep "\t" -j 4 "awk -v var={2} '$awk_cmd' INFILE" :::: LISTFILE >/dev/null
real 0m28.190s
user 1m42.750s
sys 0m1.757s我对 这 的回答:
1:
The awk1 script does not run much faster than the awk script.
在我看来,节省15%的时间是相当重要的。
I suspect because it scans the LISTFILE for every line in the INFILE.
是的,基本上。awk1脚本只循环一次INFILE。
So number of lines scanned using the array with for (i in a) = NR(INFILE)*NR(LISTFILE).
关。但是不要忘记,通过使用数组,我们实际上删除了LISTFILE中的任何重复值。
This is the same number of lines you would scan by going through the INFILE repeatedly with the bash script.
因此,只有当LISTFILE不包含重复项时,此语句才为真。即使LISTFILE从来不包含任何陷阱,也最好避免多次读取单个文件。
2:
Running awk and awk2 in a different folder produced different results (where my 4 min result came from versus the ~2 min result here, not sure what the difference is because they are next door in the parent directory.
什么四分钟的结果?当对这类事情进行基准测试时,您应该停止将输出写入磁盘。如果您的机器在运行测试时有一些后台进程,那么您的结果只会以磁盘的写入速度出现偏差。使用/dev/null代替。
3:
Awk and Awk2 are essentially the same. Any idea why awk2 runs faster?
如果将管道移到sort和uniq,您将更好地了解时差在哪里。您会发现,执行$4 > i - 5 && $4 < i + 5与执行$4 < i + 5 && $4 > i - 5完全不同。如果awkout.txt与awkout.txt相同,则需要花费时间处理副本。
4:
这里发布的第二个命令避免了这个测试:$4 > i - 5 && $4 < i + 5。我不认为光是这一点就能保证运行时有90%的改进。有些东西闻起来不对劲。您介意重新运行您的测试,写到/dev/null,并张贴LISTFILE和INFILE的内容吗?如果这两个文件是机密的,您能否提供一些示例文件,其中包含等于原件的内容量?
其他想法:
在我看来,类似于这样的东西也是可行的:
awk 'FNR==NR { for (i=$2-4;i<$2+5;i++) a[i]; next } $4 in a { b[$10,$4] } END { print length b }' LISTFILE INFILE发布于 2014-06-12 23:10:41
看起来,您只需要将LISTFILE的键添加到数组中,然后,在处理INFILE (逐行)时,使用'if‘语句测试数组中的每个键。您可以使用以下构造或类似的结构来完成此操作:
for (i in a) { print i, a[i] }以下是一些未经测试的代码,可以帮助您入门。请注意,我没有为我的键分配任何值:
awk 'FNR==NR { a[$2]; next } { for (i in a) { if ($4 > i - 5 && $4 < i + 5) { print $10, $4 } } }' LISTFILE INFILE发布于 2014-06-18 21:34:34
斯蒂夫上面的答案是这个问题的正确答案。下面是数组和非数组处理问题的方法的比较。
我创建了一个测试程序来查看两种不同的场景和每个场景的结果。测试程序代码如下:
echo time for bash
time for line in `awk '{print $2}' $1` ; do awk -v a=$line '$4>a-5&&$4<a+5{print $4,$10}' $2 ; done | sort | uniq -c > bashout.txt
echo time for awk
time awk 'FNR==NR{a[$2]; next}{for (i in a) {if ($4>i-5&&$4<i+5) print $10,$4}}' $1 $2 |sort | uniq -c > awkout.txt
echo time for awk2
time awk 'FNR==NR{a[$2]; next}{for (i in a) {if ($4<i+5&&$4>i-5) print $10,$4}}' $1 $2 |sort | uniq -c > awk2out.txt
echo time for awk3
time awk '{a=$2;b=$1;for (i=a-4;i<a+5;i++) print b,i}' $1 > LIST2;time awk 'FNR==NR{a[$2];next}$4 in a{print $10,$4}' LIST2 $2 | sort | uniq -c > awk3out.txt这是输出:
time for bash
real 2m22.394s
user 2m15.938s
sys 0m6.409s
time for awk
real 2m1.719s
user 2m0.919s
sys 0m0.782s
time for awk2
real 1m49.146s
user 1m47.607s
sys 0m1.524s
time for awk3
real 0m0.006s
user 0m0.000s
sys 0m0.001s
real 0m12.788s
user 0m12.096s
sys 0m0.695s4.意见/问题
https://stackoverflow.com/questions/24192269
复制相似问题