Synchronisierungsrechte

Planungsmechaniken

Die Datenverarbeitung in einem MediaPipe-Diagramm erfolgt innerhalb von Verarbeitungsknoten, die als abgeleitete CalculatorBase-Klassen definiert sind. Das Planungssystem entscheidet, wann jeder Rechner ausgeführt wird.

Jedes Diagramm hat mindestens eine Planerwarteschlange. Jede Planerwarteschlange hat genau einen executor. Knoten werden einer Warteschlange (und somit einem Executor) statisch zugewiesen. Standardmäßig gibt es eine Warteschlange, deren Executor ein Thread-Pool mit einer Anzahl von Threads ist, die auf den Funktionen des Systems basiert.

Jeder Knoten hat einen Planungsstatus, der nicht bereit, bereit oder wird ausgeführt sein kann. Eine Bereitschaftsfunktion bestimmt, ob ein Knoten zur Ausführung bereit ist. Diese Funktion wird bei der Initialisierung der Grafik aufgerufen, wenn die Ausführung eines Knotens beendet ist und sich der Status der Eingaben eines Knotens ändert.

Die verwendete Bereitschaftsfunktion hängt vom Knotentyp ab. Ein Knoten ohne Streameingaben wird als Quellknoten bezeichnet. Quellknoten können immer ausgeführt werden, bis sie dem Framework mitteilen, dass keine weiteren Daten für die Ausgabe verfügbar sind. An diesem Punkt werden sie geschlossen.

Nicht-Quellknoten sind bereit, wenn sie Eingaben zu verarbeiten haben und diese Eingaben einen gültigen Eingabesatz gemäß den von der Eingaberichtlinie des Knotens festgelegten Bedingungen bilden (siehe unten). Die meisten Knoten verwenden die Standardeingaberichtlinie, einige Knoten jedoch auch eine andere.

Wenn ein Knoten bereit ist, wird eine Aufgabe zur entsprechenden Planerwarteschlange hinzugefügt, die eine Prioritätswarteschlange ist. Die Prioritätsfunktion ist derzeit festgelegt und berücksichtigt die statischen Eigenschaften der Knoten und ihre topologische Sortierung im Diagramm. Beispielsweise haben Knoten, die näher an der Ausgabeseite des Diagramms liegen, eine höhere Priorität, während Quellknoten die niedrigste Priorität haben.

Jede Warteschlange wird von einem Executor bereitgestellt, der für die tatsächliche Ausführung der Aufgabe durch Aufrufen des Codes des Rechners verantwortlich ist. Sie können verschiedene Executors bereitstellen und konfigurieren. Damit lässt sich die Verwendung von Ausführungsressourcen anpassen, z. B. indem bestimmte Knoten auf Threads mit niedrigerer Priorität ausgeführt werden.

Zeitstempelsynchronisierung

Die Ausführung von MediaPipe-Diagrammen erfolgt dezentral: Es gibt keine globale Uhr und verschiedene Knoten können Daten von verschiedenen Zeitstempeln gleichzeitig verarbeiten. Dies ermöglicht einen höheren Durchsatz über Pipeline.

Zeitinformationen sind jedoch für viele Wahrnehmungsworkflows sehr wichtig. Knoten, die mehrere Eingabestreams erhalten, müssen sie im Allgemeinen koordinieren. Ein Objektdetektor kann beispielsweise eine Liste von Begrenzungsrechtecken aus einem Frame ausgeben und diese Informationen können in einen Renderingknoten eingespeist werden, der sie zusammen mit dem ursprünglichen Frame verarbeiten sollte.

Daher besteht eine der Hauptaufgaben des MediaPipe-Frameworks darin, die Eingabesynchronisierung für Knoten bereitzustellen. In Bezug auf die Framework-Mechanik besteht die Hauptaufgabe eines Zeitstempels darin, als Synchronisierungsschlüssel zu dienen.

Darüber hinaus unterstützt MediaPipe deterministische Vorgänge, die in vielen Szenarien (Tests, Simulationen, Batch-Verarbeitung usw.) wichtig sind, während Graphautoren den Determinismus bei Bedarf lockern können, um Echtzeiteinschränkungen zu erfüllen.

Den beiden Zielen Synchronisierung und Determinismus liegen mehrere Designentscheidungen zugrunde. Insbesondere müssen die Pakete, die in einen bestimmten Stream übertragen werden, kontinuierlich ansteigende Zeitstempel haben. Dies ist nicht nur eine nützliche Annahme für viele Knoten, sondern auch von der Synchronisierungslogik. Jeder Stream hat eine Zeitstempelgrenze. Dies ist der niedrigstmögliche Zeitstempel, der für ein neues Paket im Stream zulässig ist. Wenn ein Paket mit dem Zeitstempel T ankommt, geht die Grenze entsprechend der monotonen Anforderung automatisch zu T+1 über. So weiß das Framework mit Sicherheit, dass nicht mehr Pakete mit einem Zeitstempel unter T ankommen.

Eingaberichtlinien

Die Synchronisierung wird lokal auf jedem Knoten mithilfe der vom Knoten angegebenen Eingaberichtlinie durchgeführt.

Die durch DefaultInputStreamHandler definierte Standardeingaberichtlinie bietet die deterministische Synchronisierung von Eingaben mit folgenden Garantien:

  • Wenn Pakete mit demselben Zeitstempel in mehreren Eingabestreams bereitgestellt werden, werden sie unabhängig von ihrer Eingangsreihenfolge in Echtzeit immer zusammen verarbeitet.

  • Eingabesätze werden in streng aufsteigender Zeitstempelreihenfolge verarbeitet.

  • Es werden keine Pakete verworfen und die Verarbeitung ist vollständig deterministisch.

  • Der Knoten ist unter Berücksichtigung der oben genannten Garantien so schnell wie möglich bereit, Daten zu verarbeiten.

Um seine Funktionsweise zu erklären, müssen wir die Definition eines gesetzten Zeitstempels einführen. Wir sagen, dass ein Zeitstempel in einem Stream berechnet wird, wenn er unter der Zeitstempelgrenze liegt. Mit anderen Worten: Ein Zeitstempel wird für einen Stream festgelegt, sobald der Status der Eingabe zu diesem Zeitstempel unwiderruflich bekannt ist: Entweder ist ein Paket vorhanden oder es gibt die Sicherheit, dass ein Paket mit diesem Zeitstempel nicht ankommen wird.

Ein Zeitstempel wird für mehrere Streams festgelegt, wenn er für jeden dieser Streams festgelegt wird. Wenn ein Zeitstempel festgelegt ist, impliziert dies außerdem, dass alle vorherigen Zeitstempel ebenfalls festgelegt sind. Somit können festgelegte Zeitstempel deterministisch in aufsteigender Reihenfolge verarbeitet werden.

Basierend auf dieser Definition steht ein Rechner mit der Standardeingaberichtlinie zur Verfügung, wenn es einen Zeitstempel gibt, der für alle Eingabestreams gilt und ein Paket in mindestens einem Eingabestream enthält. Die Eingaberichtlinie stellt alle verfügbaren Pakete für einen festgelegten Zeitstempel als einzelnen Eingabesatz für den Rechner bereit.

Eine Konsequenz dieses deterministischen Verhaltens besteht darin, dass bei Knoten mit mehreren Eingabestreams theoretisch unbegrenzt auf die Begleichung eines Zeitstempels gewartet werden kann und dass eine unbegrenzte Anzahl von Paketen zwischenzeitlich gepuffert werden kann. Betrachten Sie einen Knoten mit zwei Eingabestreams, von dem einer weiter Pakete sendet, während der andere nichts sendet und die Begrenzung nicht weitergibt.

Daher stellen wir auch benutzerdefinierte Eingaberichtlinien bereit, z. B. das Aufteilen der Eingaben in verschiedene Synchronisierungssätze, die durch SyncSetInputStreamHandler definiert werden, oder die Synchronisierung ganz und die Verarbeitung von Eingaben sofort, wenn sie durch ImmediateInputStreamHandler definiert werden.

Ablaufsteuerung

Es gibt zwei Hauptmechanismen zur Ablaufsteuerung. Ein Rückdruckmechanismus drosselt die Ausführung von Upstream-Knoten, wenn die in einem Stream gepufferten Pakete ein (konfigurierbares) Limit erreichen, das durch CalculatorGraphConfig::max_queue_size definiert wird. Dieser Mechanismus sorgt für deterministisches Verhalten und umfasst ein System zur Vermeidung von Deadlocks, das konfigurierte Limits bei Bedarf lockert.

Das zweite System besteht aus dem Einfügen spezieller Knoten, die Pakete gemäß Echtzeiteinschränkungen löschen können (in der Regel mit benutzerdefinierten Eingaberichtlinien), die durch FlowLimiterCalculator definiert werden. Bei einem gemeinsamen Muster wird beispielsweise ein Ablaufsteuerungsknoten am Eingang einer Teilgrafik platziert, mit einer Loopback-Verbindung von der Endausgabe zum Ablaufsteuerungsknoten. Der Ablaufsteuerungsknoten kann somit verfolgen, wie viele Zeitstempel in der nachgelagerten Grafik verarbeitet werden, und Pakete verwerfen, wenn diese Anzahl eine (konfigurierbare) Grenze erreicht. Und da Pakete vorgelagert werden, vermeiden wir die vergeudete Arbeit, die durch die teilweise Verarbeitung eines Zeitstempels und das anschließende Verwerfen von Paketen zwischen den Zwischenphasen entstehen würde.

Dieser rechnerbasierte Ansatz gibt dem Autor der Grafik die Kontrolle darüber, wo Pakete gelöscht werden können. Außerdem ermöglicht er die Flexibilität, das Verhalten der Grafik je nach Ressourceneinschränkungen anzupassen und anzupassen.