¿Cómo garantiza una protección de resources una queue de envío en serie?

//my_serial_queue is a serial_dispatch_queue dispatch_async(my_serial_queue, ^{ //access a shanetworking resource such as a bank account balance [self changeBankAccountBalance]; }); 

Si presento 100 tareas que cada usuario accede y cambia el saldo de una count bancaria, entiendo que una queue serie ejecutará cada tarea secuencialmente, pero ¿estas tareas terminan secuencialmente también cuando se usa dispatch_async?

¿Qué pasa si la tarea # 23 que presento de forma asíncrona a la queue de serie tarda mucho time para terminar? ¿La tarea n. ° 24 comenzaría solo cuando se completara la tarea n. ° 23 o la tarea n. 24 comenzaría antes de la tarea n. ° 23? Si es así, ¿no podría la tarea # 24 tener el saldo incorrecto de la count bancaria cuando comienza su trabajo, arruinando así la integridad de los datos?

¡¡Gracias!!

man dispatch_queue_create dice: "Todas las grabaciones de memory realizadas por un bloque enviado a una queue de serie están garantizadas para que sean visibles para los bloques posteriores enviados a la misma queue". Por lo tanto, las queues en serie son una buena manera de serializar el acceso al estado mutable para evitar condiciones de carrera .

¿Estas tareas terminan secuencialmente también cuando se usa dispatch_async?

Sí. La queue dicta la política de ejecución, no la forma en que pone en queue el bloque.

En otras palabras, si la queue es de serie, hacer queue con asíncrono o synchronization no cambia eso. La única diferencia es: ¿espero que este bloque se complete antes de continuar con la ejecución del rest del progtwig? dispatch_async = no, dispatch_sync = yes.

¿Qué pasa si la tarea # 23 que presento de forma asíncrona a la queue de serie tarda mucho time para terminar?

Nada cambia. Una queue en serie siempre espera que el bloque previamente eliminado (# 23) se complete antes de borrar y ejecutar el siguiente bloque (# 24). Si el locking de la queue es una preocupación, debe implementar un time de espera dentro de su código de bloque.

Sí, una queue de serie dedicada es una forma maravillosa de sincronizar el acceso a algunos resources compartidos entre varios subprocesss. Y, sí, con una queue de serie, cada tarea esperará a que la anterior se complete.

Dos observaciones:

  1. Si bien esto suena como un process altamente ineficiente, esto está implícitamente en el corazón de cualquier técnica de synchronization (ya sea basada en queue o enfoque basado en locking) cuyo objective es minimizar las actualizaciones concurrentes de un recurso compartido.

    Pero en muchos escenarios, la técnica de queue de serie puede generar un performance significativamente mejor que otras técnicas comunes, como el simple locking de mutex, NSLock o la directiva @synchronized . Para una discusión sobre las técnicas de synchronization alternativas, consulte la sección Sincronización de la Guía de progtwigción de subprocesss. Para ver una discusión sobre el uso de queues en lugar de lockings, consulte el apartado Eliminación de códigos basados en locking en la sección Migración fuera de los hilos de la Guía de progtwigción de concurrency.

  2. Una variación del patrón de queue serie es usar el patrón "lector-escritor", donde crea una queue simultánea GCD:

     queue = dispatch_queue_create("identifier", DISPATCH_QUEUE_CONCURRENT); 

    A continuación, realiza lecturas utilizando dispatch_sync , pero realiza las escrituras usando dispatch_barrier_async . La networking efectiva es permitir operaciones de lectura simultáneas, pero asegúrese de que las escrituras nunca se realicen simultáneamente.

    Si su recurso permite lecturas simultáneas, el patrón lector-escritor puede ofrecer una mayor ganancia de performance que la de una queue en serie.

Por lo tanto, en resumen, si bien parece ineficaz que la tarea # 24 espere la tarea # 23, eso es inherente a cualquier técnica de synchronization en la que se esfuerce por minimizar las actualizaciones concurrentes del recurso compartido. Y las queues en serie de GCD son un mecanismo sorprendentemente eficiente, a menudo mejor que muchos mecanismos de locking simples. El patrón lector-escritor puede, en alguna circunstancia, ofrecer aún más mejoras de performance.


Mi respuesta original, a continuación, fue en respuesta a la pregunta original, que era confusa, titulada "¿Cómo garantiza la concurrency de una queue de envío en serie?" En retrospectiva, esto fue solo un uso accidental de los términos incorrectos.


Esta es una opción interesante de palabras, "¿cómo garantiza una concurrency de envíos en serie la concurrency?"

Hay tres types de queues , serie, concurrente y la queue principal. Una queue de serie, como su nombre indica, no comenzará el siguiente bloque enviado hasta que el anterior haya finalizado. (Usando su ejemplo, esto significa que si la tarea 23 toma mucho time, no comenzará la tarea 24 hasta que se complete). Algunas veces esto es crítico (por ejemplo, si la tarea 24 depende de los resultados de la tarea 23 o si ambas tareas 23 y 24 intentan acceder al mismo recurso compartido).

Si desea que estas varias tareas enviadas se ejecuten simultáneamente entre ellas, utilice una queue simultánea (una de las queues simultáneas globales que obtiene a través de dispatch_get_global_queue , o puede crear su propia queue simultánea mediante dispatch_queue_create con la opción DISPATCH_QUEUE_CONCURRENT ) . En una queue simultánea, muchas de las tareas enviadas se pueden ejecutar al mismo time. El uso de queues simultáneas requiere cierto cuidado (especialmente la synchronization de los resources compartidos), pero puede generar importantes beneficios de performance cuando se implementa correctamente.

Y como un compromiso entre estos dos enfoques, puede usar queues de operación, que pueden ser concurrentes, pero en las que también puede restringir cuántas de las operaciones de la queue se ejecutarán simultáneamente en cualquier momento mediante el establecimiento de maxConcurrentOperationCount . Un escenario típico en el que usará esto es cuando realiza tareas de networking en segundo plano, donde no desea más de cinco requestes de networking simultáneas.

Para get más información, consulte la Guía de progtwigción de concurrency .