Suche…


Einführung

Grand Central Dispatch (GCD) ist Apples Antwort auf Multithreading. Es handelt sich um ein einfaches Framework, um Aufgaben synchron oder asynchron in Warteschlangen auszuführen und CPU-Threads für Sie hinter den Kulissen zu verarbeiten.

Verwandte Themen: Parallelität

Erstellen Sie eine Versandwarteschlange

Sie können Ihre eigene Warteschlange mit dispatch_queue_create erstellen

Ziel c

dispatch_queue_t queue = dispatch_queue_create("com.example.myqueue",  DISPATCH_QUEUE_SERIAL);

Schnell

// Before Swift 3
let queue = dispatch_queue_create("com.example.myqueue", DISPATCH_QUEUE_SERIAL)
// Swift 3
let queue = DispatchQueue(label: "com.example.myqueue") //default is serial queue, unless .concurrent is specified as an attribute otherwise

Die Hauptwarteschlange abrufen

Die Hauptwarteschlange ist die Versandwarteschlange, in der alle Aktualisierungen der Benutzeroberfläche stattfinden und der Code, der Änderungen an der Benutzeroberfläche beinhaltet, platziert wird.

Sie müssen zur Hauptwarteschlange gelangen, um die Benutzeroberfläche nach Abschluss eines asynchronen Prozesses wie NSURLSession

Es gibt zwei Arten von Hauptwarteschlangenaufrufen, synchronous und asynchronous . Wenn Sie etwas synchronously aufrufen, bedeutet dies, dass der Thread, der diesen Vorgang initiiert hat, auf die Beendigung der Aufgabe wartet, bevor Sie fortfahren. Asynchronous bedeutet, dass es nicht wartet.

Code Objective-C

Synchronous Aufruf der Hauptwarteschlange

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

Asynchronous Aufruf der Hauptwarteschlange

dispatch_async(dispatch_get_main_queue(), ^{
   // do work here to Usually to update the User Interface
});

SWIFT 3

Asynchronous Aufruf der Hauptwarteschlange

DispatchQueue.main.async {

}

Synchronous Aufruf der Hauptwarteschlange

DispatchQueue.main.sync {

}

Versandgruppe

DispatchGroup ermöglicht die Aggregation der Arbeitssynchronisation. Sie können sie verwenden, um mehrere verschiedene Arbeitselemente zu senden und zu verfolgen, wann alle abgeschlossen sind, auch wenn sie in verschiedenen Warteschlangen ausgeführt werden. Dieses Verhalten kann hilfreich sein, wenn keine Fortschritte erzielt werden können, bis alle angegebenen Aufgaben abgeschlossen sind.

Ein Szenario, in dem dies nützlich sein kann, ist, wenn Sie mehrere Webservice-Aufrufe haben, die alle beendet werden müssen, bevor Sie fortfahren. Beispielsweise müssen Sie mehrere Datensätze herunterladen, die von einer Funktion verarbeitet werden müssen. Sie müssen warten, bis alle Webservices abgeschlossen sind, bevor Sie die Funktion aufrufen, um alle empfangenen Daten zu verarbeiten.

Swift 3

func doLongTasksAndWait () {
    print("starting long running tasks")
    let group = DispatchGroup()          //create a group for a bunch of tasks we are about to do
    for i in 0...3 {                     //launch a bunch of tasks (eg a bunch of webservice calls that all need to be finished before proceeding to the next ViewController)
        group.enter()                    //let the group know that something is being added
        DispatchQueue.global().async {   //run tasks on a background thread
            sleep(arc4random() % 4)      //do some long task eg webservice or database lookup (here we are just sleeping for a random amount of time for demonstration purposes)
            print("long task \(i) done!")
            group.leave()                //let group know that the task is finished
        }
    }
    group.wait()                         //will block whatever thread we are on here until all the above tasks have finished (so maybe dont use this function on your main thread)
    print("all tasks done!")
}

Wenn Sie nicht warten möchten, bis die Gruppen abgeschlossen sind, sondern stattdessen eine Funktion ausführen möchten, nachdem alle Aufgaben abgeschlossen sind, verwenden Sie die notify anstelle der group.wait()

group.notify(queue: DispatchQueue.main) { //the queue: parameter is which queue this block will run on, if you need to do UI updates, use the main queue
    print("all tasks done!")              //this will execute when all tasks have left the group
}

Beispielausgabe:

starting long running tasks
long task 0 done!
long task 3 done!
long task 1 done!
long task 2 done!
all tasks done!

Weitere Informationen finden Sie in den Apple Docs oder im verwandten Thema

Dispatch Semaphore

DispatchSemaphore bietet eine effiziente Implementierung eines traditionellen Zählsemaphors, mit dem der Zugriff auf eine Ressource über mehrere Ausführungskontexte gesteuert werden kann.

Ein Szenario für die Verwendung eines Semaphors kann beispielsweise beim Lesen / Schreiben von Dateien auftreten. Wenn mehrere Tasks gleichzeitig aus einer Datei lesen und schreiben möchten, kann dies die Leistung erhöhen, wenn jede Task warten muss um den E / A-Controller nicht zu überlasten.

Swift 3

func do2TasksAtATime () {
    print("starting long running tasks (2 at a time)")
    let sem = DispatchSemaphore(value: 2)            //this semaphore only allows 2 tasks to run at the same time (the resource count)
    for i in 0...7 {                                 //launch a bunch of tasks
        DispatchQueue.global().async {               //run tasks on a background thread
            sem.wait()                               //wait here if no resources available
            sleep(2)                                 //do some long task eg file access (here we are just sleeping for a 2 seconds for demonstration purposes)
            print("long task \(i) done! \(Date())")
            sem.signal()                             //let the semaphore know this resource is now available
        }
    }
}

Beispielausgabe: (Beachten Sie die Zeitstempel)

starting long running tasks (2 at a time)
long task 0 done! 2017-02-16 07:11:53 +0000
long task 1 done! 2017-02-16 07:11:53 +0000
long task 2 done! 2017-02-16 07:11:55 +0000
long task 3 done! 2017-02-16 07:11:55 +0000
long task 5 done! 2017-02-16 07:11:57 +0000
long task 4 done! 2017-02-16 07:11:57 +0000
long task 6 done! 2017-02-16 07:11:59 +0000
long task 7 done! 2017-02-16 07:11:59 +0000

Weitere Informationen finden Sie in den Apple Docs

Serielle versus gleichzeitige Dispatch-Warteschlangen

Swift 3

Serienwarteschlange

func serialQueues () {
    let serialQueue = DispatchQueue(label: "com.example.serial") //default queue type is a serial queue
    let start = Date ()
    for i in 0...3 {                                             //launch a bunch of tasks
        serialQueue.async {                                      //run tasks on a background thread, using our serial queue
            sleep(2)                                             //do some long task eg webservice or database lookup
            let timeTaken = Date().timeIntervalSince(start)
            print("serial long task \(i) done! total time taken: \(timeTaken)")
        }
    }
}

Beispielausgabe:

serial long task 0 done! total time taken: 2.07241100072861
serial long task 1 done! total time taken: 4.16347700357437
serial long task 2 done! total time taken: 6.23209798336029
serial long task 3 done! total time taken: 8.30682599544525

Gleichzeitige Warteschlange

func concurrentQueues () {
    let concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent) //explicitly specify the queue to be a concurrent queue
    let start = Date ()
    for i in 0...3 {            //launch a bunch of tasks
        concurrentQueue.async { //run tasks on a background thread, using our concurrent queue
            sleep(2)            //do some long task eg webservice or database lookup
            let timeTaken = Date().timeIntervalSince(start)
            print("concurrent long task \(i) done! total time taken: \(timeTaken)")
        }
    }
}

Beispielausgabe:

concurrent long task 3 done! total time taken: 2.07092100381851
concurrent long task 0 done! total time taken: 2.07087397575378
concurrent long task 2 done! total time taken: 2.07086700201035
concurrent long task 1 done! total time taken: 2.07089096307755

Diskussion

Wie aus den obigen Beispielen ersichtlich, wird eine serielle Warteschlange jede Aufgabe in der Reihenfolge abschließen, in der sie an die Warteschlange übergeben werden. Jede Aufgabe wartet, bis die vorherige Aufgabe abgeschlossen ist, bevor sie ausgeführt wird. Bei der gleichzeitigen Warteschlange wartet jede Aufgabe nicht auf die anderen in der Warteschlange und wird so bald wie möglich ausgeführt. Der Vorteil ist, dass alle Tasks in der Warteschlange gleichzeitig in separaten Threads ausgeführt werden, sodass eine gleichzeitige Warteschlange weniger Zeit als eine serielle Warteschlange benötigt.

Wenn die Reihenfolge der Ausführung von Aufgaben nicht wichtig ist, verwenden Sie immer eine gleichzeitige Warteschlange, um die beste Effizienz zu erzielen.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow