https://www.raywenderlich.com/5370-grand-central-dispatch-tutorial-for-swift-4-part-1-2

Dies ist die Fortsetzung der Concurrency in Swift-Serie. Siehe Teil 1 und Teil 2, um die Grundlagen zu verstehen

In diesem Teil werden die folgenden Themen behandelt

  1. Was sind Operationen und ihre Lebenszustände
  2. Erstellen Sie einen Block, NSInvocationOperation und benutzerdefinierte Operationen, um Aufgaben asynchron auszuführen
  3. Abbrechen von Vorgängen
  4. Was sind Operationswarteschlangen
  5. So fügen Sie Vorgänge in Vorgangswarteschlangen hinzu
  6. So erstellen Sie Abhängigkeiten zwischen Vorgängen
  7. Vorteile von Vorgangswarteschlangen gegenüber GCD
  8. Versandgruppenimplementierung mithilfe von Vorgangswarteschlangen

Operationen sind ein objektorientierte Methode zum Kapseln von Arbeiten, die Sie asynchron ausführen möchten.

Ein Operationsobjekt ist eine Instanz der Operation or NSOperation -Klasse (im Foundation framework), mit der Sie die Arbeit kapseln, die Ihre Anwendung ausführen soll.An operation object is an instance of the Operation or NSOperation class (in the Foundation framework)that you use to encapsulate work you want your application to perform.

Die Operationsklasse selbst ist eine abstrakte Basisklasse, die in Unterklassen unterteilt werden muss, um nützliche Arbeit zu leisten. Obwohl diese Klasse abstrakt ist, bietet sie eine erhebliche Infrastruktur, um den Arbeitsaufwand in Ihren eigenen Unterklassen zu minimieren. Darüber hinaus bietet das Foundation Framework zwei konkrete Unterklassen, die Sie unverändert mit Ihrem vorhandenen Code verwenden können.

Operations State

Eine Operation hat eine Zustandsmaschine, die ihren Lebenszyklus darstellt. Es gibt mehrere mögliche Zustände, die an verschiedenen Stellen dieses Lebenszyklus auftreten:

  • Wenn es instantiated ist, wechselt es in den Zustand isReady.
  • Wenn wir die start -Methode aufgerufen haben, wechselt sie in den Zustand isExecuting.
  • Wenn die Aufgabe finished ist, wechselt sie zu isFinished
  • Wenn die Aufgabe ausgeführt wird und Sie cancel aufrufen, wechselt sie in den Zustand isCancelled, bevor Sie in den Zustand isFinished übergeht

Es gibt hauptsächlich drei Möglichkeiten, Operationen zu erstellen

BlockOperation (Konkrete Klasse)

Eine Klasse, die Sie verwenden, um ein oder mehrere Blockobjekte gleichzeitig auszuführen. Da es mehr als einen Block ausführen kann, arbeitet ein Blockoperationsobjekt mit einer Gruppensemantik; erst wenn alle zugehörigen Blöcke die Ausführung beendet haben, gilt die Operation selbst als abgeschlossen.. Im Blockbetrieb können Sie Operationsabhängigkeiten, KVO, Benachrichtigungen und Stornierungen nutzen.

Wie in Abbildung 1 gezeigt, haben wir diesen Code async ausgeführt, was bedeutet, dass er sofort zurückkehrt, aber die schlechte Nachricht ist, dass er den Hauptthread blockiert, da operation.start() im Hauptthread aufgerufen wurde

Operationsobjekte werden standardmäßig synchron ausgeführt — das heißt, sie führen ihre Aufgabe in dem Thread aus, der ihre start -Methode aufruft.

Abbildung 1

Was zum Teufel ist synchron und führen Sie ein oder mehrere Blockobjekte gleichzeitig aus.

Wie in Abbildung 1.0.1 gezeigt, wie Sie sehen können, werden die Aufgaben / Blöcke, die der Blockoperation selbst hinzugefügt wurden, gleichzeitig ausgeführt, aber der Block läuft synchron, was bedeutet, dass er den Thread blockiert, bei dem start aufgerufen wird In unserem Fall ist es Hauptthread

Abbildung 1.0.1

Wie in Abbildung 1.0.2 gezeigt, wird dieser Thread blockiert, da wir die Start-Methode für einen anderen Thread aufrufen

Abbildung 1.0.2

Wie in Abbildung 1.0.3 gezeigt, können wir auch einen Vervollständigungsblock hinzufügen, der aufruft, wenn alle gleichzeitigen Blöcke ausgeführt werden

Abbildung 1.0.3

Führen Sie die Blockoperation gleichzeitig aus

Wie in Abbildung 1 gezeigt.1 da wir die Methode start() in einem Hintergrundthread aufrufen, führt sie ihre Aufgabe im Thread aus. Es gibt eine coole Möglichkeit, dies mithilfe der Operation Queue zu tun, und wir werden dies später sehen.

Abbildung 1.1

NSInvocationOperation (Konkrete Klasse)

Eine Klasse, die Sie verwenden, um ein Operationsobjekt basierend auf einem Objekt und Selektor aus Ihrer Anwendung zu erstellen.

In Objective C können wir NSInvocationOperation erstellen, während es in Swift nicht verfügbar ist.

https://developer.apple.com/library/archive/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationObjects/OperationObjects.html#//apple_ref/doc/uid/TP40008091-CH101-SW6

3. Benutzerdefinierte Operationen

Die Unterklasse Operation gibt Ihnen die vollständige Kontrolle über die Implementierung Ihrer eigenen Operationen, einschließlich der Möglichkeit, die Standardausführung Ihrer Operation zu ändern und ihren Status zu melden.

Wie in Abbildung 2 gezeigt, haben wir benutzerdefinierte Operationen erstellt, indem wir sie von der Basisklasse Operation unterklassifiziert und ihre Methode main überschrieben haben. Wenn Sie eine Unterklasse erstellen, setzen Sie Ihre Aufgabe auf die Methode main. Wir haben eine nicht gleichzeitige benutzerdefinierte Operation implementiert und in diesem Fall den Hauptthread blockiert

Abbildung 2

Wenn Sie vorhaben, Vorgänge manuell auszuführen und sie dennoch asynchron ausführen möchten, müssen Sie die entsprechenden Maßnahmen ergreifen, um dies sicherzustellen. Dazu definieren Sie Ihr Operationsobjekt als gleichzeitige Operation.

Wie in Abbildung 3 gezeigt, haben wir die folgenden Schritte ausgeführt, um die Aufgabe gleichzeitig auszuführen

  1. Erstellte Unterklasse MyConcurrentQueue . Tippfehler: Der Name sollte sein MyConcurrentOperations
  2. Aufruf start() Methode ruft main() Methode auf Hintergrundthread
  3. Bei der Hauptmethode haben wir unsere Aufgabe definiert und eine Sache zu beachten Wir können auch den Fall abbrechen
  4. Beim Aufruf von cancel Bei der benutzerdefinierten Operation wird in den Zustand isCancelled übergegangen und die Schleife unterbrochen, und wie in Abbildung 3 gezeigt, werden nur 39487 Elemente gedruckt

Abbildung 3

Operation Queues

  1. Operations Queues sind Cocoas High-Level-Abstraktion auf GCD
  2. Mit Operation Queues Sie werden die wahre Macht der Operationen sehen, anstatt die Operation selbst zu starten, geben Sie sie der Operation Queue, die dann die Planung und Ausführung übernimmt.
  3. Vorgangswarteschlangen sind eine objektorientierte Methode zum Kapseln von Arbeiten, die Sie asynchron ausführen möchten.
  4. Sie fügen operations (Aufgaben / Arbeit) zu operation queue hinzu und wir haben besprochen, wie wir Operationen mit zwei Methoden erstellen können.

Operationen hinzufügen

Wie in Abbildung 4 gezeigt, haben wir zwei Operationen (mit Block) erstellt und in die Operationswarteschlange eingefügt. Die Operationswarteschlange hat beide Operationen in einem Hintergrundthread gestartet und ausgeführt. Keine Notwendigkeit, start() Methode auf benutzerdefinierten Thread 🆒 aufzurufen. Wenn wir der Operationswarteschlange eine Operation hinzufügen, wird sie ausgeführt, sobald sie fertig ist

Abbildung 4

Wie in Abbildung 5 gezeigt, haben wir die Aufgabe nur seriell ausgeführt, oder Sie können sagen, dass wir die serielle Warteschlange mithilfe von Operationswarteschlangen implementiert haben. Bitte beachten Sie meinen Teil 1, wenn Sie nicht wissen, was die serielle Warteschlange ist, indem Sie Folgendes festlegen maxConcurrentOperationCount = 1

maxConcurrentOperationCount → Die maximale Anzahl von Operationen in der Warteschlange, die gleichzeitig ausgeführt werden können. Der Standardwert ist -1, was bedeutet, dass das System entscheiden soll

Abbildung 5

Durch Setzen von maxConcurrentOperationCount = 2 haben wir eine gleichzeitige Warteschlange erstellt und jetzt werden Aufgaben gleichzeitig ausgeführt, wie in Abbildung gezeigt 6

Abbildung 6

Operationsabhängigkeiten

Wie in Abbildung 7 gezeigt, haben wir erneut eine serielle Warteschlange erstellt, indem wir Abhängigkeiten zwischen zwei Aufgaben hinzugefügt haben. Wir haben zwei Blockoperationen erstellt und sagen, dass Task 1 erst gestartet wird, wenn Task 2 durch Aufrufen beendet ist blockOperations1.addDependency(blockOperations2)

Abbildung 7

Versandgruppenimplementierung mit Operations Queue

In Teil 2 haben wir die GCD-Versandgruppenfunktion verwendet, um einen Thread zu blockieren, bis eine oder mehrere Aufgaben ausgeführt wurden. Wie in Abbildung 8 gezeigt, haben wir das gleiche Verhalten mithilfe von Operationswarteschlangen mithilfe von Abhängigkeiten implementiert. Dies ist sehr hilfreich, wenn Sie erst dann Fortschritte erzielen können, wenn alle angegebenen Aufgaben abgeschlossen sind.

Wie in Abbildung 8 gezeigt, haben wir drei Aufgaben und wir wollten gleichzeitig ausführen und wenn alle Aufgaben abgeschlossen sind, müssen wir eine Methode aufrufen, um anzuzeigen, dass alle Aufgaben abgeschlossen sind und was wir getan haben

  1. Erstellt eine Operationswarteschlange
  2. Erstellt drei Blockoperationen, die Aufgaben ausführen
  3. Erstellt eine Abschlussblockoperation (blockOperations4), die ausgelöst wird, wenn alle drei Aufgaben abgeschlossen sind
  4. Machte blockOperations4 abhängig von blockOperations1, blockOperations2 und blockOperations3 was bedeutet, dass blockOperations4 ausgeführt wird, wenn alle drei Aufgaben abgeschlossen sind
  5. waitUntilFinished → Blockiert die Ausführung des aktuellen Threads, bis das Operationsobjekt seine Aufgabe beendet da wir den aktuellen Thread, der main ist, nicht blockieren möchten, weisen wir ihn mit false
  6. Führen Sie diesen Code aus und „Alle Operationen sind abgeschlossen“ wird gedruckt, wenn task1, task2 und task3 beendet sind

Abbildung 8

Wie in Abbildung 9 gezeigt, blockieren wir einfach den Hauptthread, indem wir waitUntilFinished = true. Die Frage ist also, wann es hilfreich ist, und Sie erhalten die Antwort im nächsten Abschnitt

Abbildung 9

Wie in Abbildung 10 gezeigt, haben wir ein Dispatch-Gruppenverhalten mit der Operation Queue implementiert, ohne Abhängigkeiten zu verwenden, was wir getan haben Wir haben die Funktion waitUntilFinished entsprechend verwendet . Wenn Sie sich im Hintergrundthread befinden, können Sie diesen Thread blockieren, um dieses Verhalten zu erreichen. Ich habe absichtlich mit der DispatchQueue.global().async -Methode zum Hintergrundthread gewechselt, siehe Teil 1, um diesen Code zu verstehen

Wir haben der Operationswarteschlange mitgeteilt, Task 1, Task 2 und Task 3 in der Operationswarteschlange auszuführen und den aktuellen Thread zu blockieren, bis diese gleichzeitigen Tasks ihre Ausführung beenden

Abbildung 10

Vorteile von Operation Queues über GCD

  1. Die Operation API bietet Unterstützung für Abhängigkeiten. Sie können komplexe Abhängigkeiten zwischen Aufgaben sehr einfach erstellen, obwohl Sie dies in GCD erreichen können, aber Sie müssen viel Arbeit leisten.
  2. Die Klassen NSOperation und NSOperationQueue verfügen über eine Reihe von Eigenschaften, die mithilfe von KVO (Key Value Observing) beobachtet werden können. Dies ist ein weiterer wichtiger Vorteil, wenn Sie den Status eines Vorgangs oder einer Vorgangswarteschlange überwachen möchten.
  3. Vorgänge können angehalten, fortgesetzt und abgebrochen werden. Sobald Sie eine Aufgabe mit Grand Central Dispatch versenden, haben Sie keine Kontrolle mehr über die Ausführung dieser Aufgabe. Die NSOperation API ist in dieser Hinsicht flexibler und gibt dem Entwickler die Kontrolle über den Lebenszyklus der Operation
  4. Die NSOperationQueue fügt dem Mix auch eine Reihe von Vorteilen hinzu. Sie können beispielsweise die maximale Anzahl von Operationen in der Warteschlange angeben, die gleichzeitig ausgeführt werden können. Auf diese Weise können Sie einfach steuern, wie viele Vorgänge gleichzeitig ausgeführt werden, oder eine Warteschlange für serielle Vorgänge erstellen.

Demnächst

Im nächsten Teil werden wir uns den tatsächlichen Anwendungsfall der Erstellung einer benutzerdefinierten Operation ansehen

Nützliche Links

· https://developer.apple.com/library/archive/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationObjects/OperationObjects.html#//apple_ref/doc/uid/TP40008091-CH101-SW1

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.