Bash Jobs Parallelisieren

Es gibt Anforderungen bei denen es nötig ist viele Befehle – möglicherweise mit verschiedenen Parametern – schnell ab zu arbeiten. Dabei kann man sich der Anzahl an Cores in einem Server (oder auch PC) bedienen. Eine Anforderung wäre zum Beispiel, dass immer so viele Prozesse gestartet werden, wie auch Prozessoren verfügbar sind. Das ganze möglichst ohne viel Drumherum – also ohne viel Installationsaufwand.

Eine ganz simple Möglichkeit stellt folgendes Script dar. Als Parameter wird jeweils der komplette Befehl angegeben. Standardmäßig laufen immer so viele Prozesse gleichzeitig wie Prozessoren vorhanden sind. Diese Zahl kann aber auch manuell vorgegeben werden. Das restliche Management übernimmt das Script selbst.

#!/bin/bash
#
# Ronny Becker, 05.2009
#


NUM=0
QUEUE=""
MAX_NPROC="none"

USAGE="A simple wrapper for running processes in parallel.
Usage: `basename $0` [-h] [-q] [-r] [-j nb_jobs] command command command command command command command command ...
 	-h		Shows this help
	-j nb_jobs 	Set number of simultanious jobs [def. CPU Count]
	-q 		be quiet - do not output any information (but errors)
 Examples:
 	`basename $0` somecommand somecommand somecommand ..."

# subs
function queue {
	QUEUE="$QUEUE $1"
	NUM=$(($NUM+1))
}

function regeneratequeue {
	OLDREQUEUE=$QUEUE
	QUEUE=""
	NUM=0
	for PID in $OLDREQUEUE
	do
		if [ -d /proc/$PID  ] ; then
			QUEUE="$QUEUE $PID"
			NUM=$(($NUM+1))
		fi
	done
}

function checkqueue {
	OLDCHQUEUE=$QUEUE
	for PID in $OLDCHQUEUE
	do
		if [ ! -d /proc/$PID ] ; then
			regeneratequeue # at least one PID has finished
			break
		fi
	done
}

# parse command line
if [ $# -eq 0 ]; then #  must be at least one arg
	echo "$USAGE" >&2
	exit 1
fi

while getopts j:qh OPT; do # "j:" waits for an argument "h" doesnt
    case $OPT in
	h)	echo "$USAGE"
		exit 0 ;;
	j)	MAX_NPROC=$OPTARG ;;
	q)	BE_QUIET=1 ;;
	\?)	# getopts issues an error message
		echo "$USAGE" >&2
		exit 1 ;;
    esac
done

# get cpu information (cpu count = MAX_NPROC)
if [[ "$MAX_NPROC" =~ "none" ]]; then
 CPUs=`cat /proc/cpuinfo | grep -c "processor.*[0-9]$" 2>/dev/null`
 if [ $CPUs -gt 0 ]
 then
  MAX_NPROC=$CPUs
  if [ ! $BE_QUIET ]; then echo "Found $MAX_NPROC CPUs - using $MAX_NPROC parallel threads"; fi
 else
  MAX_NPROC=2
  if [ ! $BE_QUIET ]; then echo "Setting number of simultanous jobs to 2 - could not get CPU information"; fi
 fi
fi

# Main program
shift `expr $OPTIND - 1` # shift input args, ignore processed args

# Count all Jobs
CMD_COUNT=$#
CMD_COUNT_ACT=0

# run forest run !!
while [ $# -gt 0 ] # for the rest of the arguments
do
	# statistics
        CMD_COUNT_ACT=$(($CMD_COUNT_ACT + 1))
	# define command
	CMD="$1"
        shift
       
	if [ ! $BE_QUIET ]; then echo -e "`date \"+%d.%m.%Y %H:%M:%S\"`: \033[1m [${CMD_COUNT_ACT}/${CMD_COUNT}]\033[0m Starting \033[1m${CMD}\033[0m"; fi

	# run command
	eval "$CMD &"

	PID=$!
	queue $PID

	while [ $NUM -ge $MAX_NPROC ]; do
		checkqueue
		sleep 0.6
	done
done
wait # wait for all processes to finish before exit
if [ ! $BE_QUIET ]; then echo -e "`date \"+%d.%m.%Y %H:%M:%S\"`: \033[1m all procs finished \033[0m"; fi

Das Original Script funktioniert ein wenig anders. Zu finden ist es hier

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>