Grundlegendes zu dispatch_async

233

Ich habe Fragen zu diesem Code

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSData* data = [NSData dataWithContentsOfURL: 
      kLatestKivaLoansURL];
    [self performSelectorOnMainThread:@selector(fetchedData:) 
      withObject:data waitUntilDone:YES];
});

Der erste Parameter dieses Codes ist

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 

Bitten wir diesen Code, serielle Aufgaben für eine globale Warteschlange auszuführen, deren Definition selbst lautet, dass er eine globale gleichzeitige Warteschlange mit einer bestimmten Prioritätsstufe zurückgibt?

Was ist der Vorteil dispatch_get_global_queuegegenüber der Hauptwarteschlange?

Ich bin verwirrt. Könnten Sie mir bitte helfen, dies besser zu verstehen?

user2332873
quelle
1
Sie sollten Ihren Code besser in mehrere Zeilen schneiden, damit er sinnvoller ist. Schützen Sie Ihr dispatch_get_global_queueInneres in einem variablen Typ von dispatch_queue_t myQueue. Es ist besser lesbar, wenn Sie nur myQueue an Ihre `` dispatch_async` übergeben
Alex Cio

Antworten:

517

Der Hauptgrund, warum Sie die Standardwarteschlange über der Hauptwarteschlange verwenden, besteht darin, Aufgaben im Hintergrund auszuführen.

Wenn ich beispielsweise eine Datei aus dem Internet herunterlade und den Benutzer über den Fortschritt des Downloads aktualisieren möchte, führe ich den Download in der Prioritätsstandardwarteschlange aus und aktualisiere die Benutzeroberfläche in der Hauptwarteschlange asynchron.

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    //Background Thread
    dispatch_async(dispatch_get_main_queue(), ^(void){
        //Run UI Updates
    });
});
David
quelle
Ich verstehe, dass David sich für Ihre Antwort bedankt, aber meine Frage war eher dazu da, die Logik zu verstehen, dies zu tun, dh diesen Code zu bitten, serielle Aufgaben in der globalen Warteschlange auszuführen, die gleichzeitig die Warteschlange selbst ist
user2332873
Ich mache genau das, was Sie vorschlagen, aber irgendwie wird die uiTableViewCell nicht sofort aktualisiert, wenn ich [self.tableView reloadData] in den Run UI-Updates aufrufe. Es dauert ungefähr 4 oder 5 Sekunden. Es macht mich seit einigen Tagen verrückt .
GrandSteph
@ GrandSteph Ich bin mit dieser Methode nicht allzu vertraut. Möglicherweise dauert die Ausführung dieser Methode nur 5 Sekunden. Das Wichtigste bei dispatch_async ist, dass Sie damit Dinge im Hintergrund erledigen können, ohne den Haupt-Thread aufzuhängen.
David
2
Was bedeutet das 0?
Honig
3
@Honey Die 0 ist der flagsParameter, der derzeit absolut nichts tut. Aus den Dokumenten:Flags that are reserved for future use. Always specify 0 for this parameter.
David
199

Alle DISPATCH_QUEUE_PRIORITY_X-Warteschlangen sind gleichzeitige Warteschlangen (dh sie können mehrere Aufgaben gleichzeitig ausführen) und sind FIFO in dem Sinne, dass Aufgaben in einer bestimmten Warteschlange in der Reihenfolge "first in, first out" ausgeführt werden. Dies ist im Vergleich zur Hauptwarteschlange (von dispatch_get_main_queue ()), bei der es sich um eine serielle Warteschlange handelt (Aufgaben werden in der Reihenfolge ausgeführt und beendet, in der sie empfangen werden).

Wenn Sie also 1000 dispatch_async () -Blöcke an DISPATCH_QUEUE_PRIORITY_DEFAULT senden, werden diese Aufgaben in der Reihenfolge ausgeführt, in der Sie sie in die Warteschlange gestellt haben. Ebenso für die Warteschlangen HIGH, LOW und BACKGROUND. Alles, was Sie in eine dieser Warteschlangen senden, wird im Hintergrund in alternativen Threads außerhalb Ihres Hauptanwendungsthreads ausgeführt. Daher eignen sich diese Warteschlangen zum Ausführen von Aufgaben wie Herunterladen im Hintergrund, Komprimieren, Berechnen usw.

Beachten Sie, dass die Ausführungsreihenfolge FIFO pro Warteschlange ist. Wenn Sie also 1000 dispatch_async () - Aufgaben an die vier verschiedenen gleichzeitigen Warteschlangen senden, diese gleichmäßig aufteilen und in der richtigen Reihenfolge an BACKGROUND, LOW, DEFAULT und HIGH senden (dh Sie planen die letzten 250 Aufgaben in der HIGH-Warteschlange), ist dies sehr wahrscheinlich Die ersten Aufgaben, die beim Starten angezeigt werden, befinden sich in dieser HIGH-Warteschlange, da das System impliziert hat, dass diese Aufgaben so schnell wie möglich zur CPU gelangen müssen.

Beachten Sie auch, dass ich sage "wird in der richtigen Reihenfolge ausgeführt", aber denken Sie daran, dass bei gleichzeitigen Warteschlangen die Ausführung nicht unbedingt in der richtigen Reihenfolge abgeschlossen wird, abhängig von der Zeitdauer für jede Aufgabe.

Laut Apple:

https://developer.apple.com/library/content/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html

Eine gleichzeitige Versandwarteschlange ist nützlich, wenn Sie mehrere Aufgaben haben, die parallel ausgeführt werden können. Eine gleichzeitige Warteschlange ist immer noch eine Warteschlange, da sie Aufgaben in einer First-In- und First-Out-Reihenfolge aus der Warteschlange entfernt. Eine gleichzeitige Warteschlange kann jedoch zusätzliche Aufgaben aus der Warteschlange entfernen, bevor frühere Aufgaben abgeschlossen sind. Die tatsächliche Anzahl der Aufgaben, die zu einem bestimmten Zeitpunkt von einer gleichzeitigen Warteschlange ausgeführt werden, ist variabel und kann sich dynamisch ändern, wenn sich die Bedingungen in Ihrer Anwendung ändern. Viele Faktoren beeinflussen die Anzahl der von den gleichzeitigen Warteschlangen ausgeführten Aufgaben, einschließlich der Anzahl der verfügbaren Kerne, des Arbeitsaufwands anderer Prozesse sowie der Anzahl und Priorität der Aufgaben in anderen seriellen Versandwarteschlangen.

Wenn Sie diese 1000 dispatch_async () -Blöcke an eine DEFAULT-, HIGH-, LOW- oder BACKGROUND-Warteschlange senden, werden sie grundsätzlich alle in der Reihenfolge ausgeführt, in der Sie sie senden. Kürzere Aufgaben können jedoch vor längeren erledigt werden. Gründe dafür sind, ob CPU-Kerne verfügbar sind oder ob die aktuellen Warteschlangenaufgaben rechenintensive Arbeit leisten (was das System glauben lässt, dass es unabhängig von der Anzahl der Kerne zusätzliche Aufgaben parallel versenden kann).

Der Grad der Parallelität wird vollständig vom System verwaltet und basiert auf der Systemlast und anderen intern festgelegten Faktoren. Dies ist das Schöne an Grand Central Dispatch (dem System dispatch_async ()): Sie erstellen Ihre Arbeitseinheiten einfach als Codeblöcke, legen eine Priorität für sie fest (basierend auf der von Ihnen ausgewählten Warteschlange) und lassen das System den Rest erledigen.

Um Ihre obige Frage zu beantworten: Sie sind teilweise richtig. Sie "bitten diesen Code", gleichzeitige Aufgaben in einer globalen gleichzeitigen Warteschlange mit der angegebenen Prioritätsstufe auszuführen. Der Code im Block wird im Hintergrund ausgeführt, und jeder zusätzliche (ähnliche) Code wird möglicherweise parallel ausgeführt, abhängig von der Bewertung der verfügbaren Ressourcen durch das System.

Die "Haupt" -Warteschlange hingegen (von dispatch_get_main_queue ()) ist eine serielle Warteschlange (nicht gleichzeitig). Aufgaben, die an die Hauptwarteschlange gesendet werden, werden immer in der richtigen Reihenfolge ausgeführt und immer in der richtigen Reihenfolge beendet. Diese Aufgaben werden auch im UI-Thread ausgeführt, sodass Sie Ihre UI mit Fortschrittsmeldungen, Abschlussbenachrichtigungen usw. aktualisieren können.

SimplePanda
quelle
+1, aber ich denke in der Praxis spielt es keine Rolle, ob gleichzeitige Warteschlangen FIFO oder nur zufällige Reihenfolge sind. Wenn Sie 5 Aufgaben in einer Schleife starten, gehen Sie davon aus, dass sie im Wesentlichen zur gleichen Zeit gestartet werden. Es gibt keine Garantie dafür, dass z. B. die erste E / A-Operation der ersten Aufgabe vor der fünften erfolgt, selbst wenn sie denselben Code ausführen. OTOH, für serielle Warteschlangen ist das FIFO-Verhalten wesentlich, und meiner Meinung nach ist dies der entscheidende Unterschied zwischen den beiden Warteschlangentypen.
Gerhard Wesp
Unglaubliche Erklärung. Klatscht viel!
Okhan Okbay
36

Schnelle Version

Dies ist die Swift-Version von Davids Objective-C-Antwort. Sie verwenden die globale Warteschlange, um Dinge im Hintergrund auszuführen, und die Hauptwarteschlange, um die Benutzeroberfläche zu aktualisieren.

DispatchQueue.global(qos: .background).async {
    
    // Background Thread
    
    DispatchQueue.main.async {
        // Run UI Updates
    }
}
Suragch
quelle