我正在使用while循环来处理任务,
从一个大文件中读取大约1000万行的记录。
我发现随着时间的推移,处理变得越来越慢。
我用一百万行作为模拟脚本,这揭示了问题。
但我仍然不知道为什么read
命令如何工作?
seq 1000000 > seq.dat
while read s;
do
if [ `expr $s % 50000` -eq 0 ];then
echo -n $( expr `date +%s` - $A) ' ';
A=`date +%s`;
fi
done < seq.dat
终端输出时间间隔:
98 98 98 98 98 97 98 97 98 101 106 112 121 121 127 132 135 134
大约50,000行,处理速度明显变慢。
答案 0 :(得分:4)
阅读是一个相对缓慢的过程,作为“学习Korn Shell”的作者points out *。 (在第7.2.2.1节之上。)还有其他程序,例如awk
或sed
已经过高度优化,可以执行基本相同的操作:一次从一行文件中读取并使用该输入执行一些操作。
更不用说,每次进行减法或取模数时,你都会调用外部过程,这可能会变得很昂贵。 awk
内置了这两种功能。
如下面的测试所示,awk
速度要快得多:
#!/usr/bin/env bash
seq 1000000 |
awk '
BEGIN {
command = "date +%s"
prevTime = 0
}
$1 % 50000 == 0 {
command | getline currentTime
close(command)
print currentTime - prevTime
prevTime = currentTime
}
'
输出:
1335629268
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
0
0
0
0
请注意,第一个数字相当于date +%s
。就像你的测试用例一样,我让第一场比赛成为。
注意强> 的
*是的,作者正在谈论Korn Shell,而不是OP标记的bash,但bash和ksh在很多方面都非常相似。 ksh实际上是bash的超集。所以我认为read命令与shell之间没有太大的不同。
答案 1 :(得分:3)
使用你的代码,我看到了相同的增加时间模式(从一开始!)。如果您想要更快的处理,则应使用shell内部功能重写。这是我的bash版本:
tabChar=" " # put a real tab char here, of course
seq 1000000 > seq.dat
while read s;
do
if (( ! ( s % 50000 ) )) ;then
echo $s "${tabChar}" $( expr `date +%s` - $A)
A=$(date +%s);
fi
done < seq.dat
修改强> 固定的bug,输出表明每一行都在处理,现在只有每50000行获得定时处理。 Doah!
是
if (( s % 50000 )) ;then
已修复
if (( ! ( s % 50000 ) )) ;then
现在输出echo ${.sh.version} =
版本JM 93t + 2010-05-24
50000
100000 1
150000 0
200000 1
250000 0
300000 1
350000 0
400000 1
450000 0
500000 1
550000 0
600000 1
650000 0
700000 1
750000 0
输出bash
50000 480
100000 3
150000 2
200000 3
250000 3
300000 2
350000 3
400000 3
450000 2
500000 2
550000 3
600000 2
650000 2
700000 3
750000 3
800000 2
850000 2
900000 3
950000 2
800000 1
850000 0
900000 1
950000 0
1e+06 1
至于为什么你的原始测试案例需要这么长时间......不确定。我很惊讶地看到每个测试时间和时间的增加。如果你真的需要理解这一点,你可能需要花时间来测试更多的测试内容。也许您会看到正在运行truss
或strace
的内容(取决于您的基本操作系统)。
我希望这会有所帮助。