Простой цикл для большого количества файлов в одной системе вдвое медленнее, чем в другой.
используя bash, я сделал что-то вроде
for * in ./
do
something here
done
Используя "time", я смог подтвердить, что в system2 часть "something here" работает быстрее, чем в system1. Тем не менее, весь цикл в системе 2 занимает вдвое больше, чем в системе1. Зачем? ... и как мне это ускорить?
В каталоге около 20000 (текстовых) файлов. Уменьшение количества файлов примерно до 6000 значительно ускоряет работу. Эти результаты остаются неизменными независимо от метода цикла (замена «for * in» на команду find или даже размещение имен файлов вначале в массиве).
System1: Debian (в openvz-vm с использованием reiserfs)
System2: Ubuntu (собственный, более быстрый процессор, чем System1, также более быстрый Raid5, с использованием ext3 и ext4 - результаты остаются прежними)
До сих пор я должен был исключить: оборудование (System2 должна быть намного быстрее), пользовательское программное обеспечение (bash, grep, awk, find - те же версии) и .bashrc (там нет шикарной конфигурации).
Так это файловая система? Могу ли я настроить ext3 / 4 так, чтобы он работал так же быстро, как reiserfs?
Спасибо за рекомендации!
Редактировать: Хорошо, ты прав, я должен был предоставить больше информации. Теперь я должен раскрыть свое бормотание новичка, но поехали:
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 раз, но поместить содержимое файла в переменную (FILE = (cat $i
)) удаляет перенос строки, и я больше не могу использовать awk ...? Возможно, я ошибся, поэтому, если у вас есть предложение для меня, я был бы признателен.
Тем не менее: проблема остается, что чтение файла в этом каталоге занимает слишком много времени ...
К вопросу об оборудовании: ну, system1 работает на оборудовании, которому более 5 лет, а system2 - 2 месяца. Да, спецификации совершенно разные (другие материнские платы, процессоры и т. Д.), Но system2 намного быстрее во всех остальных аспектах, а скорость записи / чтения в файловую систему также выше.
Необязательно использовать массивы в awk
за то, что вы делаете. Похоже, вы не используете запятую в качестве разделителя полей, так как вы печатаете $0
.
AWK может делать то, что у вас есть sed
и tr
делаю.
Было бы полезно посмотреть, как выглядят ваши данные.
Один из подходов может быть примерно таким (хотя смотреть на него довольно некрасиво):
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 в зависимости от фактического расположения ваших данных. Могут быть и лучшие подходы, но этот исключает порождение около 1 600 000 процессов (20 000 файлов * 20 переменных * 4 процесса / переменную), так что только около 20 000 (по одному на файл).
Вы не сказали, какое время выполнения вы получили, но с этой оптимизацией оно может быть достаточно быстрым, чтобы вы могли не торопиться, исследуя проблему в вашей новой системе.
Зависит от того, что именно вы делаете, но да, файловые системы ext работают медленно, когда у вас много файлов в одном каталоге. Разделение файлов, например, на пронумерованные подкаталоги - один из распространенных способов решения этой проблемы.
Ваше описание настолько расплывчато, что вам трудно дать совет. В любом случае, 20k файлов в одном каталоге - это много, но не НАСТОЛЬКО.
Во многих случаях можно ускорить процесс, переосмыслив то, что вы делаете. Что сейчас происходит во время вашего цикла? Вашему скрипту нужно 20 000 раз прочитать 20 000 файлов? Если да, то можно ли будет изменить ваш сценарий, чтобы он выполнял только чтение 20 000 файлов и проводил сравнение 20 000 раз? Я имею в виду: 1) прочитать файл, 2) выполнить все возможные сравнения с этим файлом, 3) перейти к следующему файлу.
Вы упомянули имена файлов в массиве, но что это означает в данном случае? Нужно ли скрипту по-прежнему выполнять 20 000 * 20 000 операций чтения вместо 20 000 операций чтения?