Unterwegs auf Erkundungstour

Es war mal wieder an der Zeit einige Kacheln für mein „Explorer Max Square“ zu sammeln. Dieses verharrt seit einer Weile bei einer Kantenlänge von 28 Kacheln und soll nach Möglichkeit bald die 30×30 erreichen.

Grober Verlauf der Tour: Grünheide – Alt-Rüdersdorf – Herzfelde – Lichtenow – Zinndorf – ehem. Nachrichtenregiment 14 – Hoppegarten – Kienbaum – Kagel – Grünheide

Besonderheiten: Sand. Sand. Sand. Die Trockenheit hat den Wegen derart zu schaffen gemacht, dass diese über weite Strecken mit dem Crosser kaum fahrbar waren. Entsprechend waren dies die anstrengendsten knapp 60 Kilometer seit langer Zeit. Dieses Fazit kommt mir irgendwie bekannt vor.

Die Tour bei Strava.

Aktuell sieht das Explorer Max Square (genaugenommen sind es derer vier) aus:

Kartendaten: © OpenStreetMap contributors

Bestimmten und reproduzierbaren Anteil von Datensätzen für Verarbeitung selektieren

Ich tat mich sehr schwer mit der Überschrift dieses Beitrags, da das Problem nicht in einem kurzen Satz zu beschreiben ist. Daher noch mal in Ruhe:

Problemstellung

Gegeben sei eine große Zahl von Bildern, welche mit verhältnismäßig hohem Aufwand an Ressourcen skaliert werden sollen. Das alles muss on-demand passieren, wenn ein Webbrowser ein Bild aufruft.

Ist ein Bild einmal skaliert, wird das Ergebnis zwischengespeichert, ein erneuter Aufruf erzeugt also keinen relevanten Aufwand. Da die Bilder in großer Zahl parallel aufgerufen werden, soll nur ein gewisser Anteil die Skalierung durchlaufen und es sollen auch immer die selben Bilder sein. Eine zufällige Auswahl scheidet also aus.

Nach und nach kann der Prozentwert erhöht werden, bis irgendwann alle Bilder skaliert sind.

Lösung

Ich habe das Problem auf die folgende Art gelöst:

  1. Wenn der Zielwert 100 % ist, wird das Bild sofort in die Weiterverarbeitung gegeben, die folgende Prüfung findet nicht statt
  2. Wenn der Zielwert 0 % ist, wird das Bild nicht weiterverarbeitet, die folgende Prüfung findet nicht statt
  3. Für alle Zielwerte größer 0 % und kleiner 100 % wird die CRC32-Checksumme der Bild-URL (die URL ist das Identifikationsmerkmal des Bildes) berechnet, das Ergebnis ist ein 32 Bit-Integer
  4. Berechnung von Checksumme Modulo 100 (ergibt die letzen beiden Stellen der Checksumme)
  5. Prüfen, ob das Ergebnis aus dem vorherigen Schritt kleiner als der angestrebte Prozentwert des Anteils zu skalierender Bilder ist, falls ja Skalierung starten, sonst übergehen

Die Verteilung der der CRC32-Checksummen im Raum der 32-Bit-Integer-Zahlen ist für diesen Zweck halbwegs gleichmäßig und zufällig. Die letzten beiden Stellen der Zahl sind also auch ausreichend gleichverteilt zwischen 0 und 100. Man kann mit dieser Methode daher relativ genau und mit wenig Aufwand einen bestimmten und reproduzierbaren Anteil der Datensätze (Bilder) selektieren.

Beispiel

Es sollen 20 % aller Bild-URLs skaliert werden.

Gegeben sei die folgende Bild-URL:

https://www.marcusjaschen.de/wp-content/uploads/2019/03/2019-03-31-DJI_0147.jpg

Die CRC32-Checksumme dieser URL ist 3556399431. Modulo 100 ergibt sich ein Ergebnis von 31.

31 ist nicht kleiner als der Zielwert 20, das Bild wird also nicht skaliert.

Eine andere Bild-URL wäre:

https://www.marcusjaschen.de/wp-content/uploads/2019/03/2019-03-31-DJI_0150.jpg

Hier lautet die Checksumme 2860930802. Modulo 100 erhält man 2, was kleiner als 20 ist, dieses Bild würde also weiterverarbeitet werden.

Linux-Shell: Prozess starten sobald ein anderer beendet ist

Ich hatte zuletzt das Problem zu lösen, dass ich einen neuen Prozess auf der Linux-Shell starten wollte, sobald ein anderer, bereits laufender Prozess beendet wurde.

Hintergrund: beide Prozesse verarbeiten Videos mit ffmpeg und haben eine Laufzeit in der Größenordnung von Tagen. Hier macht es aufgrund des Ressourcenverbrauchs wenig Sinn, beide parallel laufen zu lassen.

Hätte ich vorher gewusst, dass beide nacheinander arbeiten sollen, wäre die Lösung mit

% php encode_videos.php directory1 && \
  php encode_videos.php directory2

sehr einfach gewesen.

Der erste Prozess lief nun aber bereits. Wie startet man also den zweiten Prozess sobald der erste beendet ist?

Die Lösung heißt tail(1):

% tail -f --pid=$(pidof php) /dev/null && \
  php encode_videos.php directory2

tail hat eine Option --pid, welche die Angabe einer PID erfordert. Sobald der betreffenden Prozess beendet wird, beendet sich tail ebenfalls (mit Status-Code 0), sodass der zweite Teil des Kommandos ausgeführt wird.

(Das tail auf macOS hat diese Option nicht, das Feature ist vermutlich eine GNU-Eigenart :-))