为什么是$(

时间:2015-04-21 17:22:47

标签: performance bash input stdin cat

Debian的Bash手册建议在需要$(< file)时使用特殊命令替换$(cat 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上的命令替换的改进在很大程度上可以忽略不计。由于我的脚本需要快速循环读取大量的标准输出,我该怎么做才能加快这些读数?特别是,需要将整个stdin数据流转储到Bash变量中以进行进一步的参数替换

进一步测试:

在下面的评论和进一步测试之后,我设置10,000次迭代而不是1000次以最小化管道设置开销,并删除了复合命令语法的括号:

$ 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)现在更慢。

1 个答案:

答案 0 :(得分:3)

您忘记了与从stdin读取无关的性能成本(fork()创建子shell的成本,设置管道,等待()等待这些进程退出等等)。

$ time for i in {0..1000}; do echo str | { in=$(cat); }; done
real    0m3.183s
user    0m1.427s
sys     0m2.486s

$ time for i in {0..1000}; do echo str | { in=$(< /dev/fd/0); }; done
real    0m1.973s
user    0m0.917s
sys     0m1.844s

$ time for i in {0..1000}; do echo str | true; done
real    0m1.294s
user    0m0.708s
sys     0m1.367s

因此:

  • 使用$(cat)增加了大约(3.183s - 1.294s == 1.889s)挂历时间超过1000次迭代,与执行所有其他设置但不读取stdin的代码相比。
  • 使用$(</dev/fd/0)在1000次迭代中增加了大约(1.972s - 1.294s == 0.697s)。

这是一个2.7倍的改进,远低于你期望的每次调用1ms。