¿Diferencia entre dispatch_async y dispatch_sync en cola serie?

Creé una cola en serie como esta:

dispatch_queue_t _serialQueue = dispatch_queue_create("com.example.name", DISPATCH_QUEUE_SERIAL); 

¿Cuál es la diferencia entre dispatch_async llamado así?

  dispatch_async(_serialQueue, ^{ /* TASK 1 */ }); dispatch_async(_serialQueue, ^{ /* TASK 2 */ }); 

Y dispatch_sync llamado así en esta cola en serie?

  dispatch_sync(_serialQueue, ^{ /* TASK 1 */ }); dispatch_sync(_serialQueue, ^{ /* TASK 2 */ }); 

Según tengo entendido, independientemente de qué método de envío se utilice, TASK 1 se ejecutará y completará antes de TASK 2 , ¿correcto?

Sí. El uso de la cola en serie garantiza la ejecución en serie de las tareas. La única diferencia es que dispatch_sync solo regresa después de que el bloque finaliza, mientras que dispatch_async regresa después de que se agrega a la cola y puede que no termine.

para este código

 dispatch_async(_serialQueue, ^{ printf("1"); }); printf("2"); dispatch_async(_serialQueue, ^{ printf("3"); }); printf("4"); 

Puede imprimir 2413 o 2143 o 1234 pero 1 siempre antes de 3

para este código

 dispatch_sync(_serialQueue, ^{ printf("1"); }); printf("2"); dispatch_sync(_serialQueue, ^{ printf("3"); }); printf("4"); 

siempre imprime 1234


Nota: para el primer código, no se imprimirá 1324 . Porque printf("3") se envía después de que se ejecuta printf("2") . Y una tarea solo puede ejecutarse después de su envío.


El tiempo de ejecución de las tareas no cambia nada. Este código siempre imprime 12

 dispatch_async(_serialQueue, ^{ sleep(1000);printf("1"); }); dispatch_async(_serialQueue, ^{ printf("2"); }); 

Lo que puede suceder es

  • Subproceso 1: dispatch_async una tarea que consume tiempo (tarea 1) a la cola en serie
  • Subproceso 2: comience a ejecutar la tarea 1
  • Subproceso 1: dispatch_async otra tarea (tarea 2) en cola serie
  • Subproceso 2: finalizó la tarea 1. comience a ejecutar la tarea 2
  • Subproceso 2: finalizó la tarea 2.

y siempre ves 12

La diferencia entre dispatch_sync y dispatch_async es simple.

En ambos ejemplos, TASK 1 siempre se ejecutará antes de TASK 2 porque se envió antes.

En el ejemplo dispatch_sync , sin embargo, no enviará TASK 2 hasta después TASK 1 se haya enviado y ejecutado TASK 1 . Esto se llama “locking” . Su código espera (o “bloquea”) hasta que se ejecuta la tarea.

En el ejemplo de dispatch_async , su código no esperará a que se complete la ejecución. Ambos bloques se enviarán (y se pondrán en cola) a la cola y el rest del código continuará ejecutándose en ese hilo. Luego, en algún momento en el futuro (dependiendo de qué más haya sido enviado a su cola), se ejecutará la Task 1 y luego se ejecutará la Task 2 .

Todo está relacionado con la cola principal. Hay 4 permutaciones.

i) Serial queue, dispatch async: aquí las tareas se ejecutarán una después de la otra, pero el hilo principal (efecto en UI) no esperará el retorno.

ii) Cola en serie, sincronización de despacho: aquí las tareas se ejecutarán una después de la otra, pero el hilo principal (efecto en la IU) mostrará retraso

iii) Cola concurrente, sincronización de despacho: Aquí las tareas se ejecutarán en paralelo y el hilo principal (efecto en la interfaz de usuario) no esperará la devolución y será fluido.

iv) Cola concurrente, sincronización de despacho: aquí las tareas se ejecutarán en paralelo, pero el hilo principal (efecto en la interfaz de usuario) mostrará retraso

La elección de la cola concurrente o en serie depende de si necesita una salida de una tarea anterior para la próxima. Si dependes de la tarea anterior, adopta la cola en serie o toma la cola concurrente.

Y, por último, esta es una forma de volver al hilo principal cuando terminemos con nuestro negocio:

 DispatchQueue.main.async { // Do something here }