与猫相比,Bash而读取循环非常慢,为什么



一个简单的测试脚本在这里:

while read LINE; do
        LINECOUNT=$(($LINECOUNT+1))
        if [[ $(($LINECOUNT % 1000)) -eq 0 ]]; then echo $LINECOUNT; fi
done

当我这样做时cat my450klinefile.txt | myscript CPU锁定在100%,每秒可以处理大约1000行。大约 5 分钟在半秒内处理cat my450klinefile.txt >/dev/null所做的事情。

有没有更有效的方法可以做到这一点。我只需要从 stdin 中读取一行,计算字节数,然后将其写出到命名管道中。但即使是这个例子的速度也慢得不可思议。

每 1Gb 的输入行,我需要执行一些更复杂的脚本操作(关闭并打开一些数据馈送到的管道)。

while read如此

缓慢的原因是 shell 需要为每个字节进行系统调用。 它无法从管道读取大型缓冲区,因为 shell 不得从输入流中读取多行,因此必须将每个字符与换行符进行比较。 如果在while read循环上运行strace,则可以看到此行为。 此行为是可取的,因为它可以可靠地执行以下操作:

while read size; do test "$size" -gt 0 || break; dd bs="$size" count=1 of=file$(( i++ )); done

其中循环中的命令从 shell 从中读取的同一流中读取。 如果 shell 通过读取大型缓冲区消耗了大量数据,则内部命令将无法访问该数据。 一个不幸的副作用是read慢得离谱。

这是因为在这种情况下,

bash脚本是经过解释的,并没有真正针对速度进行优化。通常最好使用外部工具之一,例如:

awk 'NR%1000==0{print}' inputFile

与您的"每 1000 行打印一次"示例相匹配。

如果你想(对于每一行)输出行数,以字符为单位,后跟行本身,并通过另一个进程通过管道传输它,你也可以这样做:

awk '{print length($0)" "$0}' inputFile | someOtherProcess

awksedgrepcut和更强大的perl这样的工具比解释型shell脚本更适合这些任务。

每个字符串的字节计数的perl解决方案:

perl -p -e '
use Encode;
print length(Encode::encode_utf8($_))."n";$_=""' 

例如:

dd if=/dev/urandom bs=1M count=100 |
   perl -p -e 'use Encode;print length(Encode::encode_utf8($_))."n";$_=""' |
   tail

为我工作为 7.7Mb/s

要比较使用的脚本量,请执行以下操作:

dd if=/dev/urandom bs=1M count=100 >/dev/null

以 9.1Mb/s 的速度运行

似乎脚本没有那么慢:)

不太确定你的脚本应该做什么。因此,这可能不是您问题的答案,而更像是一个通用提示。

不要cat你的文件并将其管道到你的脚本,而是在使用 bash 脚本从文件中读取时,这样做:

while read line    
do    
    echo $line
done <file.txt

相关内容

  • 没有找到相关文章

最新更新