我有一个很大的输入文件,其中包含 30M 行,\r\n
.我决定做一些愚蠢的事情,并比较通过read -r
比较计算所有行的速度xargs
(剥离第\r
一个,因为xargs
似乎无法分割多个字符)。这是我的两个命令:
time tr -d '\r' < input.txt | xargs -P 1 -d '\n' -I {} echo "{}" | wc -l
time while read -r p || [ -n "$p" ]; do echo "$p"; done < input.txt | wc -l
这里,第二个解决方案是很多快点。这是为什么?
请注意,我知道这不是计算文件行数的正确方法。这个问题只是出于我的观察兴趣。
答案1
是的,正如您所怀疑的,实际上与默认命令xargs -P 1 -d '\n' -I {} echo "{}"
相同,它将分叉一个进程并在子进程中执行独立进程,同时等待其在父进程中为每行输入终止。xargs -rd '\n' -n1
echo
echo
因此,这比在同一个 shell 进程中使用低效的read
内置函数和所有内置函数要多得多的工作。echo
xargs
如果您使用 busybox而不是 GNU ,xargs
它(至少在某些配置和最新版本中)将echo
在内部调用 busybox 而无需分叉进程,您会注意到它会比bash
循环快得多。
为了进行更相关的比较,您应该比较:
tr -d '\r' | xargs -rd'\n' -n1
和
tr -d '\r' |
while IFS= read -r line || [ -n "$line" ]; do
/bin/echo "$line"
done
这可能会给您带来类似的结果,因为大部分时间将花费在分叉进程和执行独立的echo
.
在这里,关于输出seq 3e7
和测量pv -al > /dev/null
(以每秒a
平均线数来测量吞吐量),我得到了解决方案:l
- busybox xargs 为 1.12M/s
- 带有内置 echo 的 bash 循环速度为 70k/s
- GNU xargs 为 860/s
- 850/s 用于带有 /bin/echo 的 bash 循环