50000個のファイルで構成されるかなり大きなベンチマークでコマンドラインツールを評価する必要がありました。
残念ながら、このツールは並列化されておらず、このサイズのベンチマークで順番に実行するには時間がかかりました。
gnu並列(またはgnuセマフォ)についての記事をいくつか読んでいますが、gnuセマフォによって生成された複数のバックグラウンドプロセスの結果をどのように組み合わせるかを示す良い例は見つかりませんでした。コマンドラインツールをgnuセマフォでbashスクリプトにラップして並列化する
アンラップされたツールは入力パラメータとして1つのファイルを必要とするため、ツールを複数回並列に実行することによって得られるすべての結果を収集する方法を見つけなければなりませんでした。
さらに、私はクラッシュの場合に結果を失いたくはありませんでした。
スクリプトがキャンセルされるたびに、以前に処理されたファイルは再処理しないでください。
バックグラウンドプロセスworker
に十分な作業が行われるように、以下のスクリプトは複数のファイルをworker
に一度に渡します。
bashスクリプトは、私のユースケースではうまく動作します。
誰かが同様の問題を抱えている場合は、このスクリプトをあなたと共有したいと思います。 worker
関数を変更し、変数$JOBS
と$WPSIZE
を変更して、スクリプトを別のユースケースに適合させることができます。
スクリプトをより効率的にする方法に関するフィードバックを私に提供できると大変うれしいです。
おかげでたくさん、 ジュリアン
並列にFIFOへの追加#!/bin/bash
# make variables available in function started by
# gnu semaphore
export FINALRES="result.log"
export RESFIFO="/tmp/res.fifo"
export FILFIFO="/tmp/fil.fifo"
export FILELIST="/tmp/flist"
export WPSIZE=5
export JOBS=4
PUTFPID=""
WRITPID=""
# find input files fo process
find . -name "*.txt" > ${FILELIST}
# setup fifos and files
[ ! -e "${FINALRES}" ] && touch "${FINALRES}"
[ ! -e "${RESFIFO}" ] && mkfifo "${RESFIFO}"
[ ! -e "${FILFIFO}" ] && mkfifo "${FILFIFO}"
FILES=$(diff ${FINALRES} ${FILELIST} | grep '>' | cut -d '>' -f2 | tr -d ' ')
exec 4<> ${RESFIFO}
exec 5<> ${FILFIFO}
trap cleanup EXIT TERM
function cleanup() {
# write results that have been obainted so far
echo "cleanup"
[ -n "${PUTFPID}" ] && (kill -9 ${PUTFPID} 2>&1) > /dev/null
[ -n "${WRITPID}" ] && (kill -9 ${WRITPID} 2>&1) > /dev/null
rm -f "${RESFIFO}"
rm -f "${FILFIFO}"
rm -f "${LOCKFILE}"
}
# this function takes always #WPSIZE (or less) files from the fifo
function readf() {
local cnt=0
while read -r -t 2 line; do
echo "$line"
[ -z "${files}" ] && { files=${line}; let cnt=${cnt}+1; continue; }
let cnt=${cnt}+1
[ ${cnt} -eq ${WPSIZE} ] && break
done <& 5
}
# this function is called by gnu semaphore and executed in the background
function worker() {
for fil in "${@}"; do
# do something ...
echo "result" > "${RESFIFO}"
done
exit 0
}
# this function is used (at the end) to write the comutation results to a file
function writeresult() {
while read -r line; do
[ "${line}" = "quit" ] && break
echo "${line}" >> ${FINALRES}
done < ${RESFIFO}
}
# this simple helper puts all input files into a fifo
function putf() {
for fil in $FILES; do
echo "${fil}" > "${FILFIFO}"
done
}
# make function worker known to gnu semaphore
export -f worker
# put file into fifo
putf &
PUTFPID=$!
writeresult &
WRITPID=$!
while true; do
ARGS=$(readf)
[ -z "${ARGS}" ] && break
# used word spitting on purpose here (call worker with multiple params)
sem --bg --jobs "${JOBS}" worker ${ARGS}
done
sem --wait
echo "quit" > ${RESFIFO}
wait
echo "all jobs are finished"
exit 0
ご覧ください:http://www.shellcheck.net/ – Cyrus
ありがとう、私は 'sem --bg --jobs '$という単語の分割を除いて、spellcheck.net健全性チェックに従ってスクリプトを変更しました{仕事}私が意図的にやった{求人} "労働者$ {ARGS}" – Julian
'>" $ {FINALRES} "をループの外側に置くことで、それぞれの結果を個別に検索して追加する必要がなくなります。 –