並列Forループに「進行状況バー/カウンター」を追加する

並列Forループに「進行状況バー/カウンター」を追加する

この質問は私に大きなインスピレーションを与えました。Bash FORループの並列化 読み取りループ中に非常に長いタスクを含むいくつかのツールを並列化します(つまり、入力ファイルの指定されたパスで同じタスク/タスクセットを実行します。入力ファイルには約90,000行が含まれ、増加し続けます)。

PSkocikの「FIFOベースのセマフォを使用したNプロセス」の例を私のコードに「挿入」するすべての作業を完了しました...

# initialize a semaphore with a given number of tokens
open_sem(){
    mkfifo /tmp/pipe-$$
    exec 3<>/tmp/pipe-$$
    rm /tmp/pipe-$$
    local i=$1
    for((;i>0;i--)); do
        printf %s 000 >&3
    done
}

# run the given command asynchronously and pop/push tokens
run_with_lock(){
    local x
    # this read waits until there is something to read
    read -u 3 -n 3 x && ((0==x)) || exit $x
    (
     ( "$@"; )
    # push the return code of the command to the semaphore
    printf '%.3d' $? >&3
    )&
}

N=4
open_sem $N
for thing in {a..g}; do
    run_with_lock task $thing
done 

しかし、私の「古い」コードには、読み込みループに素晴らしい進行状況カウンタが組み込まれています(下のコードは省略されています)。再利用したい傾向があるecho、awk、およびprintfの奇妙な組み合わせがあることを知っています。使用される他のスクリプトのコードは、他のオンライン例などに基づいている可能性があります。整理できると確信しています...しかし、うまくいき、このコードを使う唯一の人です! :

## $temp1 is the file with 90,000 lines to read over
## $YELLOW is a global variable exported from my bashrc with the escape code for yellow text
## $GREEN is a global variable exported from my bashrc with the escape code for green text
## $CL is a global variable exported from my bashrc with the escape code for Clear Line
## $NC is a global variable exported from my bashrc with the escape code to revert text colour back to normal

num_lines="$(cat $temp1 | wc -l)"
percent_per_line="$(awk "BEGIN {print 100/$num_lines}")"
progress_percent='0'
current_line='1'

echo -ne "${CL}${YELLOW}PROGRESS: ${progress_percent}% ${NC}\r"
while read line; do
    ############################################
    ##commands to process $line data as needed##
    ############################################

    progress_percent="$(awk "BEGIN {print $progress_percent + $percent_per_line }")"
    awk -v y=$YELLOW -v nc=$NC -v progress=$progress_percent -v current_line=$current_line -v total_lines=$num_lines 'BEGIN {printf (y"\033[2KPROGRESS: %.3f%%   (%d OF %d)\n\033[1A"nc, progress, current_line, total_lines) }' 
    #I think I mixed my global var escape codes with typed out ones cause I was I forgot / have no need to export \033[2K and \033[1A for anything else?
    ((current_line++))
done < "$temp1"

echo -e "${CL}${GREEN}PROGRESS: 100.000%   (${num_lines} OF ${num_lines})${NC}"

「新しい」FIFOセマフォコードに同様の出力を持つ何かを戻す方法を見つけようとしています...

私は何をすべきかわからない! run_with_lock関数に入りますか?もしそうなら、 rates_per_line と num_lines 変数をその関数に渡す必要がありますが、$@そこに渡されます。 :(FIFOセマフォがどのように機能するかを完全に理解していないようです。必要なデータを渡すために他のセマフォメッセージタイプを使用する場合も同様です。

私が学び、発展するのに役立つので、どんな助けでも大変感謝します!

答え1

さて、それは愚かな気がします... 100%正確ではありませんが、単純なテストスクリプトで多くのテストを終えた後に処理する必要があるような気がします。

私はセマフォ全体の正確な機能的方法を「認識」できませんでした。私が見る方法は、while readループが一度にすべての「読み取り」を実行し、すべての行をいくつかのキュー(私の考えではパイプ)に追加することです。だから最初の考えは、ループの他の項目を読むことも「完全に」実行されるということでした。 (つまり、すぐに100%にジャンプ)スクリプトはwait読み取りループの後にキューを完了するために移動します。

私はもう間違ってはいけないことがわかりました!つまりrun_with_lock、ループはwhile read一度に行のみを読み取るため、呼び出し後のすべてのコードはロックが解除されると断続的にのみ実行されます。Nrun_with_lock

したがって、目標を達成するためにすべきことは、進行コードをまったく同じ場所に維持することです。それからすべてが正常です。私の考えには特別な処理は必要ありません。

欠点は、アイテムが実際に完了したときに更新するのではなく、タスクの開始時に進行状況が表示されることです。ただし、これは必要な項目に比べて微妙です。

関連情報