5

我正在使用while循环来处理任务,

它从一个大约 1000 万行的大文件中读取记录。

我发现随着时间的推移处理变得越来越慢。

我制作了一个 100 万行的模拟脚本作为打击,这揭示了问题。

但我仍然不知道为什么,该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 行时,处理速度明显变慢。

4

2 回答 2

5

使用您的代码,我看到了相同的时间增加模式(从一开始!)。如果您想要更快的处理,您应该使用 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

编辑 修复错误,输出指示正在处理每一行,现在只有每 50000 行得到定时处理。哇!

曾是

  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

至于为什么您的原始测试用例需要这么长时间......不确定。我很惊讶地看到每个测试周期的时间和时间的增加。如果您真的需要了解这一点,您可能需要花时间检测更多的测试内容。也许您会看到正在运行的东西trussstrace(取决于您的基本操作系统)。

我希望这有帮助。

于 2012-04-28T16:08:03.207 回答
4

正如“Learning the Korn Shell”的作者所指出的,阅读是一个相对缓慢的过程。(就在第 7.2.2.1 节之上。)还有其他程序,例如awksed已经高度优化以执行基本相同的操作:一次从文件中读取一行并使用该输入执行一些操作。

更不用说,每次进行减法或取模时都会调用外部进程,这可能会变得很昂贵。 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 的超集。所以我会假设读取命令在一个 shell 和另一个 shell 之间没有太大的不同。

于 2012-04-28T15:40:33.017 回答