Buscar..


Introducción

Grand Central Dispatch (GCD) es la respuesta de Apple al multihilo. Es un marco liviano para realizar tareas de forma síncrona o asíncrona en colas y maneja los hilos de la CPU para usted entre bastidores.

Tema relacionado: Concurrencia

Crear una cola de envío

Puedes crear tu propia cola usando dispatch_queue_create

C objetivo

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

Rápido

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

Conseguir la cola principal

La cola principal es la cola de envío en la que tienen lugar todas las actualizaciones de la interfaz de usuario y se coloca el código que implica los cambios de la interfaz de usuario.

NSURLSession llegar a la cola principal para actualizar la interfaz de usuario al finalizar un proceso asíncrono como NSURLSession

Hay dos tipos de llamadas de cola principales synchronous y asynchronous . Cuando invocas algo de forma synchronously , significa que el hilo que inició esa operación esperará a que la tarea termine antes de continuar. Asynchronous significa que no esperará.

Código Objetivo-C

Llamada de cola principal Synchronous

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

Llamada Asynchronous la cola principal

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

SWIFT 3

Llamada Asynchronous la cola principal

DispatchQueue.main.async {

}

Llamada de cola principal Synchronous

DispatchQueue.main.sync {

}

Grupo de despacho

DispatchGroup permite la sincronización agregada del trabajo. Puede usarlos para enviar varios elementos de trabajo diferentes y realizar un seguimiento cuando se completen, incluso aunque se ejecuten en diferentes colas. Este comportamiento puede ser útil cuando no se puede avanzar hasta completar todas las tareas especificadas.

Un escenario en el que esto podría ser útil es si tiene varias llamadas de servicio web que todas necesitan terminar antes de continuar. Por ejemplo, necesita descargar varios conjuntos de datos que deben ser procesados ​​por alguna función. Debe esperar a que todos los servicios web se completen antes de llamar a la función para procesar todos los datos recibidos.

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

Alternativamente, si no desea esperar a que finalicen los grupos, sino que desea ejecutar una función una vez que todas las tareas hayan finalizado, use la función de notify en lugar de 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
}

Ejemplo de salida:

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

Para obtener más información, consulte los documentos de Apple o el tema relacionado

Despido semáforo

DispatchSemaphore proporciona una implementación eficiente de un semáforo de conteo tradicional, que se puede usar para controlar el acceso a un recurso en múltiples contextos de ejecución.

Un escenario para cuándo usar un semáforo podría ser si está leyendo o escribiendo un archivo, si varias tareas intentan leer y escribir desde un archivo al mismo tiempo, podría aumentar su rendimiento para hacer que cada tarea espere su turno para que Para no sobrecargar el controlador de E / S.

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

Ejemplo de salida: (observe las marcas de tiempo)

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

Para más información, consulte los documentos de Apple.

Serial vs Colas de despacho concurrentes

Swift 3

Cola de serie

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

Ejemplo de salida:

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

Cola concurrente

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

Ejemplo de salida:

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

Discusión

Como podemos ver en los ejemplos anteriores, una cola en serie completará cada tarea en el orden en que se envían a la cola. Cada tarea esperará a que la tarea anterior termine antes de ejecutarse. En cuanto a la cola concurrente, cada tarea no espera a las otras en la cola y se ejecuta tan pronto como sea posible; La ventaja es que todas las tareas en la cola se ejecutarán al mismo tiempo en subprocesos separados, haciendo que una cola concurrente tome menos tiempo que una cola en serie.

Si el orden de ejecución de las tareas no es importante, siempre use una cola concurrente para la mejor eficiencia.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow