exec 6<>/dev/tcp/localhost/12345
while read -r l <&6; do
...do something with $l...
done
В результате при том, что «do something» делает одно и то же, ничего outside не меняется - процесс чтения сокета на BASH начинает со временем отжирать всё больше процессора и памяти, так что доходит до 90% загрузки одного ядра и более 80% расхода памяти.
Огромное спасибо!
Заодно ещё перекомпилировал BASH, обновив до версии 4.2 - вроде теперь полегче стало. Но нужно последить за скриптом: он сначала всегда жрал не очень много процессора и памяти, а через неделю его ядро убивало OOM Killer'ом...
У меня постоянно используется ассоциативный массив, но в нём одни и те же ключи, они просто перезаписываются в каждой итерации.
Интересно, что после использования внутреннего extended pattern matching'а (shopt -s extglob) нагрузка на процессор по сравнению с пайпом/sed'ом даже возросла. Как такое может быть...
я смотрю ты какой-то сервак на баше пишешь о_О ? то тебе инифайлы потребовалось парсить, то вот теперь по сети чего-то. может стоит задуматся о смене инструмента для проекта? я яп имею в виду.
За несколько часов потребление памяти возросло с 0.3% до 3% Это при том, что скрипт память вообще не использует, он просто берёт по одной строке из сокета и кладёт их в определённый файл (вся хитрость только в том, что каждые 5 минут это уже новый файл со свлим именем, а файл, формирующийся в данный момент, имеет в имени «тильду»). Потребление CPU возросло «всего» на 6%.
В принципе, у меня есть основной код на Perl для замены этого скрипта (дописать чуть и пустить в дело), но мне принципиально хочется разобраться в том, что, собственно, происходит.
Насчёт CPU всё-таки не совсем верно: загрузка скачет, сейчас снизилась. Но потребление памяти растёт. Явно этот скрипт умирал именно из-за того, что его прибивало OOM Killer'ом
А если попробовать на принципиально ином дистрибутиве? И что если попробовать тело цикла сделать echo $I > /dev/null? Может, проблема вовсе не в сокетах? Во время исполнения ничего не форкается? И да, может эта запись и одинакова по смыслу, но, все-же, я всегда делаю это как: cat someting | ( while read i ;do тело цикла done )
while read -r -u 6 -t 2 LINE; do
if [[ $LINE =~ ^[[:space:]]*$ ]]; then
STATE='wait 4 data stream norm-n'
(( countBlankLine++ ))
info_ "Got blank line, $countBlankLine occurence"
if (( countBlankLine>nMaxBlankLines )); then
error_ 'Limit of blank lines in block exceeded, we have to trigger a problem and wait some time'
touch $trigNoData
sleep 60
###SSH connection to the Vaisala server seems to be down. We are forced to restart overall data collector system now'
### $BIN_DIR/GLDWD.sh &
fi
sleep 1
continue
elif (( countBlankLine )); then
[[ -f $trigNoData ]] && rm -f $trigNoData
countBlankLine=0
STATE=$ST_READ_IN_CONT_LOOP
fi
oldDATE="${TS[DATE]:-$(findPrvDate)}"
if (( flGetDateFromFile )); then
REC=( $LINE )
else
REC=( 0 $(date +"%Y %m %d %H %M") )
fi
TS=([YEAR]=${REC[1]} [MONTH]=${REC[2]} [DAY]=${REC[3]} [HOUR]=${REC[4]} [MINUTE]=${REC[5]})
for v in MONTH DAY HOUR; do
[[ ${TS[$v]} =~ ^[1-9]$ ]] && TS[$v]="0${TS[$v]}"
done
TS[DATE]="${TS[YEAR]}/${TS[MONTH]}/${TS[DAY]}"
[[ ${TS[MINUTE]} =~ ^0([0-9])$ ]] && TS[MINUTE]=${BASH_REMATCH[1]}
TS[INUM]=$(( TS[MINUTE]/INTERVAL + 1 ))
(( TS[INUM] < 10 )) && TS[INUM]="0${TS[INUM]}"
DATE_PATH="$ROOT/${TS[DATE]}"
[[ -d ${DATE_PATH}/${TS[HOUR]} ]] || mkdir -p "${DATE_PATH}/${TS[HOUR]}"
if (( flFirstIter )) && [[ $oldDATE ]]; then
oldCSV=$(tail -1 "$ROOT/$oldDATE/$CSV_LST")
else
oldCSV=$CSV
fi
CSV="${TS[HOUR]}/~${CSV_FORMAT//%I%/${TS[INUM]}}"
if [[ "$oldDATE/$oldCSV" != "${TS[DATE]}/$CSV" ]]; then
debug_ "We have finished control time period"
if [[ $oldCSV && $oldCSV =~ '~' ]]; then
readyCSV="${oldCSV/\~/}"
debug_ "Rename temp file $oldCSV to $readyCSV"
mv "$ROOT"/$oldDATE/{$oldCSV,$readyCSV}
debug_ "Replace temp file name in $ROOT/$oldDATE/$CSV_LST"
sed -i "s%$oldCSV%$readyCSV%" "$ROOT"/$oldDATE/$CSV_LST
fi
echo "$CSV" >> "$DATE_PATH"/$CSV_LST
fi
echo "${LINE//+([[:space:]])/;}" >> "$DATE_PATH"/$CSV
done
я смотрю ты какой-то сервак на баше пишешь о_О ? то тебе инифайлы потребовалось парсить, то вот теперь по сети чего-то. может стоит задуматся о смене инструмента для проекта? я яп имею в виду.
+1, если у него такая страсть к скриптам, то почему бы не воспользоваться более простым средством типа питона?
Я сам догадался до unset'а, но проблему это, к сожалению, не решило. После зачистки кода и сокращения его объёма до минимума, у меня появилось нехорошее предчувствие, что дело в собственно чтении из сокета. Память явно теряет read, больше там попросту нечему течь.
Если память течёт в read, то, наверное, можно написать тестовый скрипт в несколько строчек, без массивов. Просто чтение из сокета, в который пишет, допустим, nc. Тогда есть вероятность, что ЛОРовцы позапускают его на разных версиях bash'а и можно будет оформлять баг-репорт.