我如何加快速度?

Vic*_*tor 2 sorting random bash scripting list

以下代码列出了名称和"数字",并为每个人提供了15到90岁之间的随机年龄.

#!/bin/sh

file=$1
n=$2

# if number is zero exit
if [ "$n" -eq "0" ]
then
    exit 0
fi

echo "Generating list of $n people."

for i in `seq 1 $n`;
do
    let "NUM=($RANDOM%75)+15"
    echo "name$i $NUM (###)###-####" >> $file
done

echo "List generated."
Run Code Online (Sandbox Code Playgroud)

有了它,我正在尝试列出1M名称.它很慢,我预料到了; 它太慢了,我失去了耐心,尝试了10K的名字.那也很慢,但它在几秒钟内就完成了.

我生成名称的原因是对它们进行排序.令我惊讶的是,当我对10K名称列表进行排序时,它是即时的.

怎么会这样?

是否有什么东西让这个变得不那么慢?排序和生成都是访问文件,那么排序如何更快?列表生成器中的随机数数学是什么减慢了它?

这是我的排序脚本.

#!/bin/sh
#first argument is list to be sorted, second is output file
tr -s '' < $1 | sort -n -k2 > $2
Run Code Online (Sandbox Code Playgroud)

Jam*_*son 5

使用shell生成这样的随机数并不是它的设计目的.你可能会更好地编写一些东西,用另一种语言的统一分布生成随机数,比如Fortran,Perl或C.

在你的代码中,一件非常慢的事情是从1..1e7生成一系列数字并将它们全部分配给变量.这可能非常浪费,但如果你想确定,你应该描述一下.正如混乱所指出的那样,附加到文件也可能非常昂贵!

在Python中,您可以执行以下操作:

#!/usr/bin/python
import random
count = 1

print ' '.join( ['name', 'age'] )
while count <= 1000000:
    age = random.randrange(15,90)
    count = count + 1
    name = 'name' + str(count)
    print ' '.join( [ name, str(age) ] )
Run Code Online (Sandbox Code Playgroud)

在笔记本电脑上运行需要大约10秒钟.将seq从1分配给1000000需要大约10秒,当您添加随机数生成时,您的脚本在同一台机器上花费超过三分钟.我和你一样感到沮丧,并且使用脚本来尝试让它更快.这是我正在使用的缩短版代码:

for x in `seq 1 10000`; do
   let "NUM=($RANDOM%75)+15"
   echo $NUM >> test.txt
done
Run Code Online (Sandbox Code Playgroud)

运行这个大概需要5.3s:

$ time ./test.sh
real    0m5.318s
user    0m1.305s
sys     0m0.675s
Run Code Online (Sandbox Code Playgroud)

删除文件追加并简单地将STDOUT重定向到单个文件提供以下脚本:

for x in `seq 1 10000`; do
   let "NUM=($RANDOM%75)+15"
   echo $NUM
done
Run Code Online (Sandbox Code Playgroud)

运行这个大约需要半秒钟:

$ time ./test.sh > test.txt
real    0m0.516s
user    0m0.449s
sys     0m0.067s
Run Code Online (Sandbox Code Playgroud)

程序的缓慢至少部分是由于附加到该文件.奇怪的是,当我尝试用for循环交换seq调用时,我没有注意到任何加速.


Joh*_*ica 5

for i in `seq 1 $n`
Run Code Online (Sandbox Code Playgroud)

哎呀!这会为for循环生成1,000,000个参数.这个seq电话需要很长长时间.尝试

for ((i = 1; i <= n; i++))
Run Code Online (Sandbox Code Playgroud)

顺便提一下,请注意缺少美元符号.特别是,var++语法要求您从变量名中省略美元符号.您也可以在其他地方使用或省略它们:它可以是i <= n或者$i <= $n任何一个.我想的样子,你应该忽略美元符号完全let,declarefor ((x; y; z))语句.有关sh完整说明,请参见手册页的ARITHMETIC EVALUATION部分.

  • 在我使用no-op循环体的测试中,使用seq的速度大约是C-style for循环的两倍.您使用大量内存进行交易,因为必须处理增量并在每次迭代时进行测试. (2认同)

The*_*sai 5

不是新的答案,只是新的代码.

这就是恕我直言在优秀和高效的代码之间的良好中间路径(尽可能高效,你可以在Bash,它很慢,它是一个shell ...)

for ((i=1;i<=n;i++));
do
  echo "name$i $((NUM=(RANDOM%75)+15)) (###)###-####"
done > "$file"
Run Code Online (Sandbox Code Playgroud)

替代方案,不使用经典的计数器循环

i=1
while ((i<=n)); do
  echo "name$((i++)) $((NUM=(RANDOM%75)+15)) (###)###-####"
done > "$file"
Run Code Online (Sandbox Code Playgroud)

两者速度大致相同.

修复程序与所有其他修复程序相同:

  • 不要经常关闭并重新打开文件
  • 使用shell算术
  • 啊是的,并使用QUOTES,但这是为了理智,而不是速度