当我用awk执行此操作时,它相对较快,即使它是逐行逐行(RBAR)。我试图在Bash中提供一种更快,更优雅的抗错误解决方案,该解决方案只需减少文件访问的次数即可。使用此代码使用bash遍历前1,000行可能需要10秒钟。我几乎可以同时用awk进行25次遍历所有万行文件! bash为何慢几个数量级?
FloatActionController.LittleMonkProviderHolder.sInstance
答案 0 :(得分:3)
重击很慢。就是那样子;它旨在监督特定工具的执行,并且从未针对性能进行过优化。
同样,您可以通过避免明显的低效率来降低速度。例如,read
会将其输入拆分为单独的单词,因此编写起来既更快又更清晰:
while read -r field1 field2 rest; do
# Do something with field1 and field2
代替
while read line
do
FIELD_1=`echo "$line" | cut -f1`
FIELD_2=`echo "$line" | cut -f2`
您的版本建立了两个管道,并为每一行输入至少创建了四个子级,而使用read
的设计方式则不需要任何外部过程。
如果使用cut
是因为行是制表符分隔的,而不仅仅是用空格分隔,则可以通过在本地设置read
来实现IFS
的相同效果:
while IFS=$'\t' read -r field1 field2 rest; do
# Do something with field1 and field2
即使如此,也不要指望它很快。它只会减少痛苦的速度。您最好修复awk脚本,使其不需要多次通过。 (如果您可以使用bash做到这一点,则可以使用awk并可以使用更少的代码来完成。)
注意:我设置了三个变量而不是两个变量,因为read
将行的其余部分放在最后一个变量中。如果只有两个字段,则不会造成任何伤害。 bash可以相当迅速地将变量设置为空字符串。
答案 1 :(得分:1)
正如@codeforester指出的那样,原始的bash脚本产生了许多子进程。
这是修改后的版本,可最大程度地减少开销:
#!/bin/bash
while IFS=$'\t' read -r FIELD_1 FIELD_2 others; do
if [[ "$MAIN_REF" == "$FIELD_1" ]]; then
#echo "$line"
if [[ "$FIELD_2" == "$REF_1" ]]; then
let REF_1_COUNT++
fi
let LINE_COUNT++
echo "$LINE_COUNT"
if [[ "$LINE_COUNT" == "1000" ]]; then
echo "$LINE_COUNT"
fi
fi
done < temp/refmatch
它的运行速度比原始版本快20倍,但恐怕这可能是bash脚本的局限性。