dispatch_apply toma una cola de envío como parámetro, lo que le permite elegir en qué cola ejecutar el bloque.
Tengo entendido que DispatchQueue.concurrentPerform en Swift está destinado a reemplazar dispatch_apply . Pero esta función no toma como parámetro una cola de despacho. Después de buscar en Google, encontré este tutorial de GCD que tiene este código:
let _ = DispatchQueue.global(qos: .userInitiated) DispatchQueue.concurrentPerform(iterations: addresses.count) { index in // do work here }Y explica:
Esta implementación incluye una curiosa línea de código:
let _ = DispatchQueue.global(qos: .userInitiated). Llamar a este indica que GCD use una cola con una calidad de servicio.userInitiatedpara las llamadas simultáneas.
Mi pregunta es, ¿esto realmente funciona para especificar la QoS? ¿Si es así, cómo?
Para mí, tendría sentido que no haya forma de especificar la cola para esto, porque una cola en serie no tiene sentido en este contexto y solo la QoS más alta realmente tiene sentido dado que se trata de una función de bloqueo síncrono. Pero no puedo encontrar ninguna documentación sobre por qué es posible especificar una cola con dispatch_apply pero imposible (?) Con DispatchQueue.concurrentPerform .
El intento del autor de especificar la calidad de servicio (QoS) de la cola es incorrecto. El concurrentPerform usa la QoS de la cola actual si puede. Puede confirmar esto rastreando el código fuente:
concurrentPerform llama a _swift_dispatch_apply_current .
_swift_dispatch_apply_current llama a dispatch_apply con 0 , es decir, DISPATCH_APPLY_AUTO , que se define como ...
... Constante para pasar a
dispatch_apply()odispatch_apply_f()para solicitar que el sistema use automáticamente subprocesos de trabajo que coincidan lo más posible con la configuración del subproceso actual.Al enviar un bloque para la invocación en paralelo, pasar esta constante como el argumento de la cola utilizará automáticamente la cola concurrente global que coincida más con la calidad de servicio de la persona que llama.
Esto también se puede confirmar siguiendo la llamada de dispatch_apply dispatch_apply_f en la que el uso de DISPATCH_APPLY_AUTO da como resultado la llamada a _dispatch_apply_root_queue . Si sigue dando tumbos por la madriguera del conejo de swift-corelibs-libdispatch , verá que esto realmente usa una cola global que es la misma QoS que su hilo actual.
En pocas palabras, la forma correcta de especificar la QoS es enviar la llamada a concurrentPerform a la cola deseada, por ejemplo:
DispatchQueue.global(qos: .userInitiated).async { DispatchQueue.concurrentPerform(iterations: 3) { (i) in ... } }Esto se verifica empíricamente fácilmente agregando un punto de interrupción y observando la cola en el depurador de Xcode:
No hace falta decir que la sugerencia de agregar let _ = ... es incorrecta. Considera lo siguiente:
DispatchQueue.global(qos: .utility).async { let _ = DispatchQueue.global(qos: .userInitiated) DispatchQueue.concurrentPerform(iterations: 3) { (i) in ... } }Esto se ejecutará con QoS de "utilidad", no "iniciado por el usuario".
Nuevamente, esto se verifica fácilmente empíricamente:
Consulte el video WWDC 2017 Modernizing Grand Central Dispatch para obtener una discusión sobre DISPATCH_APPLY_AUTO y concurrentPerform .