bash:循环超过20000个文件很慢 – 为什么?

对很多文件的简单循环在一个系统上比另一个快一半。

使用bash,我做了类似的事情

for * in ./ do something here done 

使用“时间”,我能够确认,在system2上的“这里的东西”部分比在system1上运行得更快。 不过,系统2上的整个循环只要在系统1上就占用双倍的时间。 为什么? …如何加快速度?

目录中有大约20000个(文本)文件。 将文件数量减less到大约6000个,大大加快了速度。 无论循环方法如何(使用find命令replace“for in”或者甚至首先将文件名放在数组中),这些发现都保持不变。

System1:Debian(在openvz-vm中,使用reiserfs)
System2:Ubuntu(原生的,比System1更快的处理器,更快的Raid5,使用ext3和ext4 – 结果保持不变)

到目前为止,我应该排除:硬件(System2应该更快),userland软件(bash,grep,awk,find是相同的版本)和.bashrc(没有spiffyconfiguration)。

那么它是文件系统? 我可以调整ext3 / 4,以便它reiserfs一样快?

感谢您的build议!

编辑:好吧,你是对的,我应该提供更多的信息。 现在我必须揭示我的初学者bash嘟but,但在这里我们去:

  declare -a UIDS NAMES TEMPS ANGLEAS ANGLEBS ELEM=0 for i in *html do #get UID UID=${i%-*html} UIDS[$ELEM]=$UID # get Name NAME=`awk -F, '/"name":"/ { lines[last] = $0 } END { print lines[last] }' ${i} | awk '{ print $2 }'` NAME=${NAME##\[*\"} NAMES[$ELEM]=$NAME echo "getting values for ["$UID"]" "("$ELEM "of" $ELEMS")" TEMPS[$ELEM]=`awk -F, '/Temperature/ { lines[last] = $0 } END { print lines[last] }' ${i} | sed 's/<[^>]*>//g' | tr -d [:punct:] | awk '{ print $3 }'` ANGLEAS[$ELEM]=`awk -F, '/Angle A/ { lines[last] = $0 } END { print lines[last] }' ${i} | sed 's/<[^>]*>//g' | tr -d [:punct:] | awk '{ print $3 }'` ANGLEBS[$ELEM]=`awk -F, '/Angle B/ { lines[last] = $0 } END { print lines[last] }' ${i} | sed 's/<[^>]*>//g' | tr -d [:punct:] | awk '{ print $3 }'` ### about 20 more lines like these ^^^ ((ELEM++)) done 

是的,问题是,我必须读取文件20次,但将文件的内容放在一个variables(文件=( cat $i ))删除linebreaks,我不能再使用awk …? 也许我尝试了这个错误,所以如果你有对我的build议,我会很感激。

仍然是:问题仍然存在,阅读该目录中的文件只需要太长时间…

对于硬件问题:好的,system1运行超过5年的硬件,system2是2个月大。 是的,规格是完全不同的(其他主板,处理器等),但是system2在其他方面速度更快,文件系统的原始写入/读取速度也更快。

取决于你在做什么,但是,当你在一个目录中有很多文件时,ext文件系统变得很慢。 将文件拆分成编号的子目录是一个常见的方法。

在你正在做的事情中,没有必要在awk使用数组。 由于您要打印$0因此您似乎没有将逗号用作字段分隔符。

AWK可以做你sedtr做的事情。

看看你的数据是什么样子会很有帮助。

一种方法可能是这样的(虽然看起来很丑):

 for f in *.html do read -r array1[i] array2[i] array3[i] array4[i] . . . <<< $( awk ' /selector1/ {var1 = $2} /selector2/ {split($0,temparray,"<[^>]*>"); split(temparray[2],temparray); var2 = gensub("[[:punct:]]","","g",a[3])} /selector3/ {split($0,temparray,"<[^>]*>"); split(temparray[2],temparray); var3 = gensub("[[:punct:]]","","g",a[3])} . . . END { print var1, var2, var3, var4 . . . }' "$f" ((i++)) done 

在awk脚本中select数组下标,并由数据的实际布局决定。 可能会有更好的方法,但是这样可以消除大约1600,000个进程(20,000个文件* 20个variables* 4个进程/ var),从而只产生大约20,000个(每个文件一个)。

你没有说你得到了什么样的执行时间,但是通过这种优化,你可以花时间在新系统中调查问题。

你的描述太模糊了,很难给你提供build议。 无论如何,在一个目录中的20K文件是很多,但不是那么多。

很多时候可以通过重新思考你所做的事来加快速度。 你的循环过程中发生了什么? 你的脚本是否需要读取20 000个文件20 000次? 如果是这样,是否有可能修改你的脚本只执行20 000个文件读取和比较20 000次? 我的意思是:1)读取文件,2)对该文件执行所有可能的比较,3)继续下一个文件。

你提到了数组中的文件名,但在这种情况下是什么意思? 脚本是否仍然需要执行20 000 * 20 000次读操作而不是20 000次读操作?