【发布时间】:2015-04-21 17:22:47
【问题描述】:
Debian 的 Bash 手册建议在需要 $(cat file) 时使用特殊的命令替换 $(< file),以提高性能,避免执行外部二进制文件。
但是,以下代码的测量完成时间大致相同:
time for i in {0..1000}; do echo str | { in=$(cat); }; done
time for i in {0..1000}; do echo str | { in=$(< /dev/fd/0); }; done
在几次运行中,它们始终分别围绕这些数字返回值:
real 0m3.665s
user 0m0.365s
sys 0m0.782s
和
real 0m2.401s
user 0m0.233s
sys 0m0.533s
因此,对于大多数用例而言,命令替换对cat 的改进在很大程度上可以忽略不计。由于我的脚本需要快速、循环地读取大量标准输入,我可以做些什么来加速这些读取?特别是,需要将整个标准输入数据流转储到 Bash 变量中以进行进一步的参数替换。
进一步测试:
在下面的 cmets 和进一步测试之后,我设置了 10,000 次迭代而不是 1000 以最小化管道设置开销,并且我删除了 compound command 语法的括号:
$ time for i in {1..10000}; do echo str | in=$(cat); done
real 0m24.754s
user 0m6.958s
sys 0m18.996s
$ time for i in {1..10000}; do echo str | in=$(< /dev/fd/0); done
real 0m33.913s
user 0m3.736s
sys 0m10.516s
这里我无法解释为什么$(< /dev/fd/0) 现在更慢了。
【问题讨论】:
-
我很困惑。您的基准测试显示了 33% 的加速。
-
...快速基准测试主要是衡量建立管道所需的时间,而不是读取标准输入的性能。也许如果您向我们展示您的实际代码,我们可以尝试帮助优化它,但事实上,您看到的数字看起来非常合理。
-
确实如此。即使想使用一种 shell 语言,ksh93(真正的 David Korne ksh,而不是克隆)也快得多。尽管我很鄙视它故意不遵守 POSIX,但 zsh 也是如此。
-
您认为增加迭代次数如何降低开销?您仍然在每次迭代中设置一次管道,因为管道在您的循环中inside。减少括号是无关紧要的 - 数千个管道的数千个子外壳是昂贵的。
-
天哪,这是真的!我没有意识到管道是在每次迭代中创建的。在
done之后将管道移出循环,极大地提高了性能。所以是的,管道是一种昂贵的小工具。
标签: performance bash input stdin cat