Diferencia entre DispatchQueue.main.async y DispatchQueue.main.sync

100

Lo he estado usando DispatchQueue.main.asyncdurante mucho tiempo para realizar operaciones relacionadas con la interfaz de usuario.



Swift proporciona ambos DispatchQueue.main.asyncy DispatchQueue.main.sync, y ambos se realizan en la cola principal.



¿Alguien puede decirme la diferencia entre ellos? ¿Cuándo debo usar cada uno?



DispatchQueue.main.async {
    self.imageView.image = imageView
    self.lbltitle.text = ""

}

DispatchQueue.main.sync {
    self.imageView.image = imageView
    self.lbltitle.text = ""
}
Aman.Samghani
fuente

Respuestas:

47

Cuando lo usa async, permite que la cola de llamadas continúe sin esperar hasta que se ejecute el bloque enviado. Por el contrario sync, la cola de llamadas se detendrá y esperará hasta que se complete el trabajo que ha enviado en el bloque. Por lo tantosync lo está sujeto a provocar interbloqueos. Intente ejecutar DispatchQueue.main.syncdesde la cola principal y la aplicación se congelará porque la cola de llamadas esperará hasta que termine el bloque enviado, pero ni siquiera podrá comenzar (porque la cola está detenida y esperando)

Cuándo usar sync ? Cuando necesita esperar a que se haga algo en una cola DIFERENTE y solo entonces continuar trabajando en su cola actual

Ejemplo de uso de sincronización:

En una cola en serie, puede usarlo synccomo mutex para asegurarse de que solo un subproceso pueda realizar el fragmento de código protegido al mismo tiempo.

Andrey Chernukha
fuente
¿Sería incorrecto llamar DispatchQueue.main.syncdesde un hilo en segundo plano?
Miel
@Honey En general, no, no hay nada de malo en una llamada de este tipo (siempre que la cola principal no haga nada pesado y requiera mucho tiempo), pero en la práctica no puedo pensar en una situación en la que realmente lo necesite. Definitivamente debería haber una solución mejor
Andrey Chernukha
1
@Honey Una de esas situaciones es actualizar una CollectionView de PHAssets desde la API de PhotoKit, como se muestra en la documentación aquí: developer.apple.com/documentation/photokit/…
taza de té
1
@teacup interesante. Me pregunto cómo sería de diferente si llamáramos asyncallí. Quiero decir, dado que no hay nada más en el hilo después, no hace ninguna diferencia. Si lo fuera, DispatchQueue.main.sync {block1}; DispatchQueue.main.sync {block2};entonces habría tenido sentido. Pero cuando no hay otro bloque, no puedo pensar en el beneficio de usar DispatchQueue.main.sync {Oneblock}over DispatchQueue.main.async {Oneblock}. Para ambos obtendrán la prioridad / inmediatez de mainQueue y nada los interrumpirá.
Cariño
3
@Honey "ya que no hay nada más en el hilo después" no es cierto cuando estás en el hilo principal, que es responsable de manejar todas las interacciones del usuario con la aplicación. Entonces, por ejemplo, un usuario puede eliminar otra foto antes de que photoLibraryDidChange regrese con una fuente de datos actualizada que cause un error de inconsistencia fatal.
taza de té
161

¿Por qué la concurrencia?

Tan pronto como agrega tareas pesadas a su aplicación, como la carga de datos, ralentiza el trabajo de la interfaz de usuario o incluso lo congela. La concurrencia le permite realizar 2 o más tareas “simultáneamente”. La desventaja de este enfoque es que la seguridad de los hilos no siempre es tan fácil de controlar. Fe cuando diferentes tareas quieren acceder a los mismos recursos, como intentar cambiar la misma variable en diferentes subprocesos o acceder a los recursos ya bloqueados por los diferentes subprocesos.

Hay algunas abstracciones que debemos conocer.

  • Colas.
  • Rendimiento de tareas sincrónico / asincrónico.
  • Prioridades.
  • Problemas comunes.

Colas

Debe ser serial o concurrente . Así como global o privada al mismo tiempo.

Con las colas en serie, las tareas se terminarán una por una, mientras que con las colas simultáneas, las tareas se realizarán simultáneamente y se terminarán en horarios inesperados. El mismo grupo de tareas llevará más tiempo en una cola en serie en comparación con una cola simultánea.

Puede crear sus propias colas privadas (tanto en serie como simultáneas ) o utilizar colas globales (del sistema) ya disponibles . La cola principal es la única cola en serie de todas las colas globales .

Se recomienda encarecidamente no realizar tareas pesadas que no estén relacionadas con el trabajo de la interfaz de usuario en la cola principal (por ejemplo, cargar datos de la red), sino realizarlas en las otras colas para mantener la interfaz de usuario descongelada y receptiva a las acciones del usuario. Si permitimos que se cambie la interfaz de usuario en las otras colas, los cambios se pueden realizar en un horario y velocidad diferentes e inesperados. Algunos elementos de la interfaz de usuario se pueden dibujar antes o después de que se necesiten. Puede bloquear la interfaz de usuario. También debemos tener en cuenta que, dado que las colas globales son colas del sistema, el sistema puede ejecutar algunas otras tareas en ellas.

Calidad de servicio / prioridad

Las colas también tienen diferentes qos (Calidad de servicio) que establecen la prioridad de ejecución de la tarea (de mayor a menor aquí):
.userInteractive - cola principal
.userInitiate - para las tareas iniciadas por el usuario en las que el usuario espera alguna respuesta
.utility - para las tareas que lleva algo de tiempo y no requiere una respuesta inmediata, por ejemplo, trabajar con datos
.background - para las tareas que no están relacionadas con la parte visual y que no son estrictas para el tiempo de finalización).

También hay

una cola .default que no transfiere la información de qos . Si no fuera posible detectar los qos la qos utilizará entre .userInitiate y .utility .

Las tareas se pueden realizar de forma sincrónica o asincrónica .

  • Sincrónico función devuelve el control a la cola actual solo después de que finaliza la tarea. Bloquea la cola y espera hasta que finalice la tarea.

  • Asincrónico función devuelve el control a la cola actual justo después de que se haya enviado la tarea para que se realice en la cola diferente. No espera hasta que termine la tarea. No bloquea la cola.

Problemas comunes.

Los errores más populares que cometen los programadores al proyectar las aplicaciones simultáneas son los siguientes:

  • Condición de carrera : se produce cuando la aplicación funciona depende del orden de ejecución de las partes del código.
  • Inversión de prioridad : cuando las tareas de mayor prioridad esperan a que finalicen las tareas de menor prioridad debido al bloqueo de algunos recursos
  • Interbloqueo : cuando algunas colas tienen una espera infinita de las fuentes (variables, datos, etc.) ya bloqueadas por algunas de estas colas.

NUNCA llame a la función de sincronización en la cola principal .
Si llama a la función de sincronización en la cola principal, bloqueará la cola y la cola estará esperando a que se complete la tarea, pero la tarea nunca se terminará ya que ni siquiera podrá comenzar debido a que la cola es ya bloqueado. Se llama punto muerto .

¿Cuándo usar la sincronización? Cuando necesitamos esperar hasta que finalice la tarea. Fe cuando nos aseguramos de que alguna función / método no se llame doblemente. Tenemos sincronización y estamos tratando de evitar que se llame dos veces hasta que esté completamente terminado. Aquí hay un código para esta preocupación:
¿Cómo averiguar qué causó el informe de bloqueo de errores en el dispositivo IOS?

Alejandro
fuente
3
No creo que "NUNCA llame a la función de sincronización en la cola principal" sea correcto. Hay casos en los que llamaría a la sincronización en el hilo principal, por ejemplo, cuando tiene un contador global que necesita que use cada objeto y aumenta: dispatchQueue.sync {count + = 1; self.orderId = count}
Elisha Sterngold
6
Clase QOS: .userInteractive NO es la cola principal.
Kunal Shah
1
¿Sería incorrecto llamar DispatchQueue.main.syncdesde un hilo en segundo plano?
Miel
1
@Honey, no, no está mal llamar así, pero según mi experiencia, te encontrarás llamando a más de DispatchQueue.main.async además de sync.
James Kim
2
¿No sería más exacto decir que nunca debería llamar a la función sync () en la cola actual? No está mal llamar a sync () en la cola principal si estás en otra cola, si lo entiendo correctamente.
ykay
0

sync o async métodos no tienen ningún efecto en la cola en la que se llaman.

syncbloqueará el hilo desde el que se llama y no la cola en la que se llama. Es la propiedad de la DispatchQueueque decide si elDispatchQueue esperará la ejecución de la tarea (cola en serie) o puede ejecutar la siguiente tarea antes de que finalice la tarea actual (cola simultánea).

Entonces, incluso cuando DispatchQueue.main.asynces una llamada asíncrona, una operación de trabajo pesado agregada puede congelar la interfaz de usuario ya que sus operaciones se ejecutan en serie en el hilo principal. Si se llama a este método desde el subproceso en segundo plano, el control volverá a ese subproceso instantáneamente incluso cuando la interfaz de usuario parezca estar congelada. Esto se debe a que la asyncllamada se realiza enDispatchQueue.main

Vipin
fuente
0

GCDle permite ejecutar una tarea synchronouslyo asynchronously[Acerca de] [Más]

synchronousLa función (bloquear y esperar) devuelve un control cuando se completará la tarea

asynchronousLa función (enviar y continuar) devuelve un control inmediatamente, enviando la tarea para que comience a una cola adecuada, pero sin esperar a que se complete.

yoAlex5
fuente