我有一个大约 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