我试图确定字符串填充的最佳性能,如下所示:
str+="A"
#one perloop
我为 bash 提供了这个脚本:
#!/bin/bash
bReport=false
nLimit=${1-3000}; #up to 25000
echo "nLimit='$nLimit'"
shopt -s expand_aliases
nStop=100000;fMaxWorkTime=1.0;
alias GetTime='date +"%s.%N"';
nTimeBegin="`GetTime`";
nDelayPart="`GetTime`";
strFinal="";
str="";
fPartWorkSleep="`bc <<< "scale=10;($fMaxWorkTime/$nStop)*$nLimit"`"
echo "fPartWorkSleep='$fPartWorkSleep'"
nCount=0;
while true;do
str+="A";
((nCount++))&&:;
if(((nCount%nLimit)==0)) || ((nCount==nStop));then
strFinal+="$str";
str="";
if $bReport;then
echo "`bc <<< "$(GetTime)-$nDelayPart"` #${#strFinal} #`bc <<< "$(GetTime)-$nTimeBegin"`";
nDelayPart="`GetTime`";
fi
sleep $fPartWorkSleep # like doing some weigthy thing based on the amount of data processed
fi;
if((nCount==nStop));then
break;
fi;
done;
echo "strFinal size ${#strFinal}"
echo "took `bc <<< "$(GetTime)-$nTimeBegin"`"
在 bash 中,最好的性能/大小是str
限制在 3000 到 25000 个字符之间(在我的机器上)。每个部分填满后,必须将其清空,并可以执行一些有重量的动作str
(并且重量与其大小有关)。
所以我的问题是,什么 shell 具有最好的字符串填充性能?根据我所曝光的内容。我愿意使用bash以外的其他shell,只是为了这种算法,如果事实证明它更快。
PS:我不得不使用 nCount 作为检查字符串大小降低性能的方法。
答案1
for sh in bash zsh yash dash mksh ksh
do printf "\n%s:\t" "$sh"
time "$sh" -c '
str="some string"
set "" ""
while ${20001+"break"}
do set "$@$@";done
IFS=A; printf %.100000s\\n "$str$*$*$*$*$*"'|
wc -c
done
bash: 100001
"$sh" -c 0.15s user 0.01s system 94% cpu 0.176 total
wc -c 0.00s user 0.00s system 1% cpu 0.175 total
zsh: 100001
"$sh" -c 0.03s user 0.01s system 97% cpu 0.034 total
wc -c 0.00s user 0.00s system 9% cpu 0.034 total
yash: 100001
"$sh" -c 0.06s user 0.01s system 94% cpu 0.067 total
wc -c 0.00s user 0.00s system 5% cpu 0.067 total
dash: 100001
"$sh" -c 0.02s user 0.01s system 92% cpu 0.029 total
wc -c 0.00s user 0.00s system 11% cpu 0.028 total
ksh: 100001
"$sh" -c 0.02s user 0.00s system 96% cpu 0.021 total
wc -c 0.00s user 0.00s system 16% cpu 0.021 total
$sh
因此,这对循环中设置的各种 shellfor
生成 100,000 个字符的字符串的速度进行了测试。这 100,000 个字符中的前 11 个是some string
as 首先设置为 的值$str
,但尾部填充为 999,989A
字符。
贝壳得到A
chars,$*
其中替换特殊 shell 参数值中的第一个字符,$IFS
作为 shell 参数数组中每个位置参数之间的串联分隔符。因为所有参数均为""
空,所以中唯一的字符$*
是分隔符。
对于循环的每次迭代,参数以指数速率累积while
- 仅break
当$20001
参数最终出现时才发生${set+}
。在那之前,while
循环基本上会执行以下操作:
### first iteration
while $unset_param; do set "" """" ""; done
### second iteration
while $unset_param; do set "" "" """" "" ""; done
### third iteration
while $unset_param; do set "" "" "" "" """" "" "" "" ""; done
...等等。
while
循环完成后$IFS
设置为A
并且特殊的 shell 参数$*
在 的尾部连接五次$str
。在将printf
结果写入 stdout 之前将%s
其修剪为最大字节数。.100000
人们可能会使用相同的策略,例如:
str='some string'
set "" ""
while ${51+"break"}; do set "$@$@"; done
shift "$((${#}-(51-${#str}))"
...这导致参数总数为 40 - 因此有 39 个分隔符...
IFS=.; printf %s\\n "$str$*"
some string.......................................
您还可以重复使用已经为不同的设置设置的相同$IFS
参数充满:
for IFS in a b c; do printf %s\\n "$str$*"; done
some stringaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
some stringbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
some stringccccccccccccccccccccccccccccccccccccccc
您还可以使用格式字符串填充空参数,printf
而不是使用$IFS
:
printf "%s m%sy%1ss%st%sr%si%sn%sg" "$str$@"
some string my string my string my string my string my string