У меня есть сценарий, в котором я распараллеливаю выполнение заданий, отслеживая прогресс. Я делаю это с помощью xargs
и именованного канала FIFO. Моя проблема в том, что я, пока xargs
работает хорошо, некоторые строки, записанные в канал, теряются. Есть идеи, в чем проблема?
Например, следующий сценарий (в основном мой сценарий с фиктивными данными) выдаст следующий результат и зависнет в конце, ожидая этих недостающих строк:
$ bash test2.sh
Progress: 0 of 99
DEBUG: Processed data 0 in separate process
Progress: 1 of 99
DEBUG: Processed data 1 in separate process
Progress: 2 of 99
DEBUG: Processed data 2 in separate process
Progress: 3 of 99
DEBUG: Processed data 3 in separate process
Progress: 4 of 99
DEBUG: Processed data 4 in separate process
Progress: 5 of 99
DEBUG: Processed data 5 in separate process
DEBUG: Processed data 6 in separate process
DEBUG: Processed data 7 in separate process
DEBUG: Processed data 8 in separate process
Progress: 6 of 99
DEBUG: Processed data 9 in separate process
Progress: 7 of 99
##### Script is hanging here (Could happen for any line) #####
#!/bin/bash
clear
printStateInLoop() {
local pipe="$1"
local total="$2"
local finished=0
echo "Progress: $finished of $total"
while true; do
if [ $finished -ge $total ]; then
break
fi
let finished++
read line <"$pipe"
# In final script I would need to do more than just logging
echo "Progress: $finished of $total"
done
}
processData() {
local number=$1
local pipe=$2
sleep 1 # Work needs time
echo "$number" >"$pipe"
echo "DEBUG: Processed data $number in separate process"
}
export -f processData
process() {
TMP_DIR=$(mktemp -d)
PROGRESS_PIPE="$TMP_DIR/progress-pipe"
mkfifo "$PROGRESS_PIPE"
DATA_VECTOR=($(seq 0 1 99)) # A bunch of data
printf '%s\0' "${DATA_VECTOR[@]}" | xargs -0 --max-args=1 --max-procs=5 -I {} bash -c "processData \$@ \"$PROGRESS_PIPE\"" _ {} &
printStateInLoop "$PROGRESS_PIPE" ${#DATA_VECTOR[@]}
}
process
rm -Rf "$TMP_DIR"
В другом сообщении я получил предложение переключиться на while read line; do … done < "$pipe"
(функция ниже) вместо while true; do … read line < "$pipe" … done
, чтобы не закрывать конвейер при каждой прочитанной строке. Это снижает частоту возникновения проблемы, но все же она возникает: некоторые строки отсутствуют, а иногда и xargs: bash: terminated by signal 13
.
printStateInLoop() {
local pipe="$1"
local total="$2"
local finished=0
echo "Progress: $finished of $total"
while [ $finished -lt $total ]; do
while read line; do
let finished++
# In final script I would need to do more than just logging
echo "Progress: $finished of $total"
done <"$pipe"
done
}
Многие люди в SO предлагали использовать parallel или pv для этого. К сожалению, эти инструменты недоступны на очень ограниченной целевой платформе. Вместо этого мой сценарий основан на xargs
.
bash linux flock write pipe
дает несколько подсказок, включая многообещающий ответ на FIFO с одним ЧИТАТЕЛЕМ и несколькими ПИСАТЕЛЯМИ в BASH - person markp-fuso   schedule 09.11.2020