ubuntuusers.de

Jobs (nur Bestimmte Anzahl von Jobs in einem Skript starten)

Status: Gelöst | Ubuntu-Version: Kein Ubuntu
Antworten |

wenze

Avatar von wenze

Anmeldungsdatum:
9. August 2006

Beiträge: 161

Wohnort: vergessen

Hallo,

ich möchte eine Jobkette in einem Skript abarbeiten. Wie kann ich mein Skript bauen, damit z.B. max 2 Jobs von meinen 100 Jobs in meinem Skript laufen?

2 gedankliche Ansätze habe ich:

  1. ( 2 Starten → nohub .....& , mit ps checken wieviele laufen, wenn einer fertig ist fertig, dann den nächsten starten )

  2. ( 2 Starten → nohub .....& , logfile des jobs checken,wenn einer fertig ist fertig, dann den nächsten starten )

Danke für den ein oder anderen Denkanstoß

Bearbeitet von rklm:

Aufzählung. Bitte die Syntax beachten!

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13204

wenze schrieb:

ich möchte eine Jobkette in einem Skript abarbeiten. Wie kann ich mein Skript bauen, damit z.B. max 2 Jobs von meinen 100 Jobs in meinem Skript laufen?

Also, Du hast eine Warteschlange von Aufträgen und willst maximal 2 Jobs gleichzeitig abarbeiten lassen.

2 gedankliche Ansätze habe ich:

  1. ( 2 Starten → nohub .....& , mit ps checken wieviele laufen, wenn einer fertig ist fertig, dann den nächsten starten )

  2. ( 2 Starten → nohub .....& , logfile des jobs checken,wenn einer fertig ist fertig, dann den nächsten starten )

Anstatt nachzuschauen ("Polling"), wie das Deine beiden Ansätze machen, ist es besser, direkt auf Ereignisse zu reagieren. Im Fall von einem beendeten Prozess ist das in der Shell das Kommando wait. Ich habe vor längerer Zeit mal so etwas gebaut:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#!/bin/bash

# DOC: Execute jobs in parallel
#
# Options
# -c cmd  command to execute
# -j int  number of parallel jobs
# -h      help

test -n "$DEBUG" && set -x

# exchange with proper job implementation or
# pass command via -c
job() {
  echo "$1: $(date)"
  sleep 4
}

# start a job
start_job() {
  "$command" "$1" &

  for ((i=0; i<${#running[@]}; ++i)); do
    if [ -z "${running[$i]}" ]; then
      running[$i]=$!
      return
    fi
  done

  running+=($!)
}

# wait for job to terminate and adjust counter
wait_job() {
  live=0

  for ((i=0; i<${#running[@]}; ++i)); do
    if [ -n "${running[$i]}" ] && kill -0 ${running[$i]} 2>/dev/null; then
      live=$((live + 1))
    else
      running[$i]=
    fi
  done

  test $live -lt $1 || wait
}

# option processing
jobs=4
command=job

while getopts ':c:j:h' opt; do
  case "$opt" in
  c)    command="$OPTARG"
        ;;
  j)    jobs="$OPTARG"
        ;;
  h)    echo ''
        echo "$(basename "$0") opts jobs..."
        echo ''
        exec sed -n '/^# DOC:/, /^[ ]*$/ s/^#\( \(DOC: *\)\?\)\?//p' "$0"
        ;;
  *)    echo "ERROR: invalid option $OPTARG" >&2
        exit 1
        ;;
  esac
done

shift $((OPTIND - 1))

# MAIN
running=()

for arg; do
  wait_job $jobs
  start_job "$arg"
done

wait_job 1

exit 0

Erläuterung, soweit ich mich erinnere: die Lösung sieht deshalb etwas kompliziert aus, weil ich mit wait_job Race Conditions Rechnung tragen musste, die auftreten können, wenn zwei Jobs gleichzeitig terminieren oder schon wieder terminiert sind während start_job noch läuft.

Man kann natürlich auch einfach GNU parallel oder xargs mit Option -n und -P nehmen. ☺

wenze

(Themenstarter)
Avatar von wenze

Anmeldungsdatum:
9. August 2006

Beiträge: 161

Wohnort: vergessen

Guten Morgen rklm,

ich bin platt 👍 . Danke Deine Vorlage muss ich mir, ehrlich gesagt, erst einmal eine Weile ansehen um sie zu verstehen.

Race Conditions Rechnung tragen musste, die auftreten können, wenn zwei Jobs gleichzeitig terminieren oder schon wieder terminiert sind während start_job noch läuft

Das war gerade das Thema, wo ich nicht so richtig weiterwusste.

Im Moment habe ich ein Skript, welches mir ein Skript erstellt, in dem die Jobs (Programmaufrufe mit Parametern) stehen, was ich bisher zu Schluss gestartet habe, und dieses quasi seriell die Jobs seriell startete.

  1. Lese alle ISO-Files aus einem Verzeichnis und erstelle mir daraus ein Skript mit dem Programmaufruf

  2. Starte das 2. Skript mit den Programmaufrufen

Ich bin versucht, jetzt das mit deinen Skript ohne das Zwischenskript zu verknüpfen, hat aber ein Nachteil, wenn ich mal unterbrechen muss oder was abgebrochen ist und ich hinterher wieder neu aufsetzen muss. Oder ich bastel noch mehr Logik rein.

Einen schönen Tag noch

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13204

wenze schrieb:

ich bin platt 👍 . Danke Deine Vorlage muss ich mir, ehrlich gesagt, erst einmal eine Weile ansehen um sie zu verstehen.

😬 Bei Fragen, fragen. ☺

Race Conditions Rechnung tragen musste, die auftreten können, wenn zwei Jobs gleichzeitig terminieren oder schon wieder terminiert sind während start_job noch läuft

Das war gerade das Thema, wo ich nicht so richtig weiterwusste.

Als Lösung dafür schaut wait_job immer nach, ob auch alle registrierten Jobs noch leben. Wenn einer davon fertig ist, dann kann man direkt schon weiter machen. Der wait am Ende wird nur dann aufgerufen, wenn alle Jobs leben. Auch da gibt es noch eine kleine Möglichkeit für eine Race-Condition.

Im Moment habe ich ein Skript, welches mir ein Skript erstellt, in dem die Jobs (Programmaufrufe mit Parametern) stehen, was ich bisher zu Schluss gestartet habe, und dieses quasi seriell die Jobs seriell startete.

  1. Lese alle ISO-Files aus einem Verzeichnis und erstelle mir daraus ein Skript mit dem Programmaufruf

  2. Starte das 2. Skript mit den Programmaufrufen

Sind Deine Jobs denn eher IO bound oder CPU bound? Im ersteren Fall lohnt sich die ganze Mühe gar nicht und ich würde einfach die ISOs sequentiell verarbeiten.

Ich bin versucht, jetzt das mit deinen Skript ohne das Zwischenskript zu verknüpfen, hat aber ein Nachteil, wenn ich mal unterbrechen muss oder was abgebrochen ist und ich hinterher wieder neu aufsetzen muss.

Das hat Du aber auch mit Deiner Variante. Um das regeln zu können, musst Du die Queue im Dateisystem speichern und immer ein Element austragen, wenn ein Job erfolgreich beendet ist.

Oder ich bastel noch mehr Logik rein.

Das wirst Du brauchen, wenn Du so etwas wie eine Wiederaufnahme möchtest. Für so persistente Queues gibt es schon reichlich. Ich kenne aber im Moment nix, was so direkt in einem Shell-Skript zu nutzen wäre.

Antworten |