为什么重定向 ≥1022 个字符的行比重定向 ≥1021 个字符的行花费 83 倍的时间?

为什么重定向 ≥1022 个字符的行比重定向 ≥1021 个字符的行花费 83 倍的时间?

我有一个大约 10 MB 的文本文件,包含大约 50k 行。当我选择所有≥1021字节的行并将输出重定向到常规文件或通过管道将其传输到cat时,需要0.135秒。当我将其更改为 ≥1022 字节时,需要 15.9 秒——延长了 83 倍。结果是相同的。

$ time grep '^.{1021,}$' my_file > /tmp/grep1021

real    0m0.135s
user    0m0.120s
sys     0m0.013s
$ time grep '^.{1022,}$' my_file > /tmp/grep1022

real    0m11.483s
user    0m11.036s
sys     0m0.441s
$ cmp /tmp/grep102?
$

此后时间消耗急剧增长;对于 ≥2100 个字符的行,需要 52 秒(结果仍然恰好相同):

$ time grep '^.{1200,}$' my_file | cat > /dev/null

real    0m15.903s
user    0m15.182s
sys     0m0.737s
$ time grep '^.{1500,}$' my_file | cat > /dev/null

real    0m27.114s
user    0m24.584s
sys     0m2.545s
$ time grep '^.{1800,}$' my_file | cat > /dev/null

real    0m36.468s
user    0m34.889s
sys     0m1.594s
$ time grep '^.{2100,}$' my_file | cat > /dev/null

real    0m52.164s
user    0m47.949s
sys     0m4.221s

这不是grep单独造成的,它本身就足够快:

$ time grep '^.{1022,}$' my_file > /dev/null

real    0m0.073s
user    0m0.060s
sys     0m0.012s
$ time grep '^.{3000,}$' my_file > /dev/null

real    0m0.495s
user    0m0.411s
sys     0m0.084s

为什么会发生这种情况?我的猜测是关于分块的,但我无法解释为什么要传递较少的数据到管道使得它需要很多处理时间更长。边界可疑地接近 1024。

系统运行 openSUSE 15.3,Linux 内核为 5.3.18-59.19-default。

更多信息:

  • 添加--line-buffered到 grep 没有什么区别
  • 使用时awk 'length >= n,进程运行速度非常快。
$ time grep '^.{1021,}$' my_file | wc
    263   30511 1899841

real    0m0.162s
user    0m0.147s
sys     0m0.031s
$ time grep '^.{1022,}$' my_file | wc
    263   30511 1899841

real    0m11.514s
user    0m11.044s
sys     0m0.487s

$ ulimit -p
8
$ time grep --line-buffered '^.{1021,}$' my_file | cat > /dev/null

real    0m0.137s
user    0m0.120s
sys     0m0.027s
$ time grep --line-buffered '^.{1022,}$' my_file | cat > /dev/null

real    0m11.528s
user    0m10.989s
sys     0m0.547s
$ time awk 'length >= 1021' my_file | cat > /dev/null

real    0m0.044s
user    0m0.041s
sys     0m0.008s
$ time awk 'length >= 1022' my_file | cat > /dev/null

real    0m0.044s
user    0m0.045s
sys     0m0.005s
$ time awk 'length >= 3000' my_file | cat > /dev/null

real    0m0.045s
user    0m0.038s
sys     0m0.012s

相关内容