首页 > 解决方案 > 加载大文件(例如:40M)后,“pwd”命令需要花费大量时间

问题描述

以下测试shell代码测试在:centOS 7 with bash shell;该代码包含三个短语;短语 1,调用 pwd 命令;短语2,读取一个大文件(cat the file);短语 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

标签: bash

解决方案


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

命令替换 --$(...)是通过fork()关闭你的 shell 的一个单独副本来实现的,在这种情况下,一个命令 -- 在这种情况下pwd-- 被执行。

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

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


两个要点:

  • 这不是pwd慢,是$( )$(true)使用或任何其他内置 shell会一样慢,而使用任何非内置命令会慢得多。

  • 根本不要使用$(pwd)——没有理由为拆分子进程来测量它的工作目录而付出代价,当你可以直接通过使用nc_result=$PWD.


推荐阅读