Ricerca…


introduzione

Grand Central Dispatch (GCD) è la risposta di Apple al multithreading. È un framework leggero per l'esecuzione di attività in modo sincrono o asincrono nelle code e gestisce i thread della CPU per te dietro le quinte.

Argomento correlato: concorrenza

Crea una coda di spedizione

Puoi creare la tua coda utilizzando dispatch_queue_create

Objective-C

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

veloce

// 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

Ottenere la coda principale

La coda principale è la coda di invio in cui si verificano tutti gli aggiornamenti dell'interfaccia utente e viene inserito il codice che comporta modifiche all'interfaccia utente.

È necessario raggiungere la coda principale per aggiornare l'interfaccia utente al termine di un processo asincrono come NSURLSession

Esistono due tipi di chiamate di coda principali synchronous e asynchronous . Quando invochi qualcosa in modo synchronously , significa che il thread che ha avviato quell'operazione attenderà che l'attività finisca prima di continuare. Asynchronous significa che non aspetterà.

Codice Obiettivo-C

Chiamata di coda principale Synchronous

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

Chiamata di coda principale Asynchronous

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

SWIFT 3

Chiamata di coda principale Asynchronous

DispatchQueue.main.async {

}

Chiamata di coda principale Synchronous

DispatchQueue.main.sync {

}

Gruppo di spedizione

DispatchGroup consente la sincronizzazione aggregata del lavoro. Puoi usarli per inviare più articoli di lavoro diversi e tracciare quando tutti sono completi, anche se potrebbero essere eseguiti su code diverse. Questo comportamento può essere utile quando non è possibile eseguire progressi finché tutte le attività specificate non sono state completate.

Uno scenario in cui questo può essere utile è se hai più chiamate al webservice che devono essere completate prima di continuare. Ad esempio, è necessario scaricare più set di dati che devono essere elaborati da una funzione. È necessario attendere il completamento di tutti i servizi Web prima di chiamare la funzione per elaborare tutti i dati ricevuti.

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!")
}

In alternativa, se non si desidera attendere il completamento dei gruppi, ma si desidera eseguire una funzione al termine di tutte le attività, utilizzare la funzione di notify al posto di 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
}

Esempio di output:

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

Per maggiori informazioni, consultare Apple Docs o l' argomento correlato

Dispatch Semaphore

DispatchSemaphore fornisce un'implementazione efficiente di un semaforo di conteggio tradizionale, che può essere utilizzato per controllare l'accesso a una risorsa attraverso più contesti di esecuzione.

Uno scenario per quando utilizzare un semaforo potrebbe essere se stai facendo un po 'di lettura / scrittura di file, se più attività stanno cercando di leggere e scrivere dal file allo stesso tempo, potrebbe aumentare le tue prestazioni per far sì che ogni attività attenda il suo turno così come non sovraccaricare il controller I / O.

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
        }
    }
}

Esempio di output: (notare i timestamp)

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

Per maggiori informazioni, fare riferimento a Apple Docs

Code di invio seriale vs simultanee

Swift 3

Coda seriale

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)")
        }
    }
}

Esempio di output:

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

Coda concomitante

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)")
        }
    }
}

Esempio di output:

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

Discussione

Come possiamo vedere dagli esempi sopra, una coda seriale completerà ogni attività nell'ordine in cui sono inviati alla coda. Ogni attività attenderà il completamento dell'attività precedente prima dell'esecuzione. Per quanto riguarda la coda concorrente, ogni attività non attende gli altri nella coda ed esegue il prima possibile; il vantaggio è che tutte le attività in coda verranno eseguite contemporaneamente su thread separati, rendendo la coda simultanea meno tempo di una coda seriale.

Se l'ordine di esecuzione delle attività non è importante, utilizzare sempre una coda concorrente per la migliore efficienza.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow