加载大文件(例如:40M)后,"pwd"命令需要花费很多时间



以下测试 shell代码测试:带有 bash shell 的 centOS 7;该代码包含三个短语;短语1,调用pwd命令;短语2,读取大文件(cat文件);短语 3,做与短语 1 相同的事情;

短语3 时间成本比短语 1 大得多(例如:21s vs 7s)

但在 MacOS 平台上,短语 1 和短语 3 的时间成本是相等的。 #!/bin/bash

#phrase 1
timeStart1=$(date +%s)
for ((ip=1;ip<=10000;ip++));
do
nc_result=$(pwd)
done
timeEnd1=$(date +%s)
timeDelta=$((timeEnd1-timeStart1))
echo $timeDelta
#phrase 2
fileName='./content.txt'   #one big file,eg. a 39M file
content=`cat $fileName`
#phrase 3
timeStart2=$(date +%s)
for ((ip=1;ip<=10000;ip++));
do
nc_result=$(pwd)
done
timeEnd2=$(date +%s)
timeDelta2=$((timeEnd2-timeStart2))
echo $timeDelta2

Slawomir的回答有问题的关键部分,但没有完整的解释。答案是什么意思"fork()"将复制原始进程的地址空间?在Unix和Linux StackExchange上有一些很好的背景。

命令替换 -$(...)- 是通过fork()掉 shell 的单独副本来实现的,命令(在本例中为pwd)在其中执行。

现在,在大多数类 UNIX 系统上,fork()非常高效,并且在执行更改这些内存块的操作之前,实际上不会复制所有内存: 每个副本都保留与原始副本相同的虚拟内存范围(因此其指针仍然有效),但 MMU 配置为在写入时抛出错误, 因此,操作系统可以静默地捕获该错误,并为每个分支分配单独的物理内存。

但是,设置配置为在更改时复制到新物理内存的页面仍然需要付费!一些平台 - 如Cygwin - 有更差/更昂贵的分叉实现;有些(显然是MacOS?)有更快的;这种差异就是你在这里测量的。


两个要点:

  • 不是pwd慢,而是$( ).使用$(true)或任何其他内置的 shell 时,它会同样慢,而对于任何非内置命令,它会慢得多

  • 根本不要使用$(pwd)- 没有理由支付拆分子进程来测量其工作目录的成本,而您可以使用nc_result=$PWD直接向父 shell 询问其工作目录。

$() 调用一个子壳。第三个命令在第二个命令运行时启动。

最新更新