Programación concurrente con GCD

Programación concurrente con GCD

Grand Central Dispatch es la respuesta de Apple a la proliferación de núcleos en los procesadores de nuestros ordenadores, tabletas y smartphones. Se trata de un framework open source de bajo nivel que simplifica enormemente la programación de hebras ("multithreaded") dejando que el sistema maneje los recursos automáticamente por nosotros. GCD combinado con la nueva sintaxis de bloques incluida en Objective C permite además mejorar la calidad del código, aumentando la legibilidad y reduciendo los errores.

Charla a cargo de Xavier Jurado Cristóbal. Contenido de Iván Leider y Xavier Jurado Cristóbal.

8837458bad71ad8edb2fbbd4dc9e8bb2?s=128

Xavier Jurado

May 14, 2012
Tweet

Transcript

  1. 2.

    Agenda - El problema: programación concurrente - Una solución: Grand

    Central Dispatch - Bloques - GCD: Runtime Engine (libdispatch) - GCD: API - Demo PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO E IVÁN LEIDER
  2. 3.

    El Problema - La programación concurrente es compleja - Race

    conditions - Deadlocks - La programación concurrente es necesaria - I/O (disco, red, dispositivos externos) - Threads - El futuro ya está aquí - Multicore: iPad 2, iPhone 4S, MacBooks, etc - Pero no solo multicore PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO E IVÁN LEIDER
  3. 4.

    La Solución - ¿Qué es Grand Central Dispatch? - API

    en C de bajo nivel para manejar tareas concurrentes - Runtime engine - Extensión del lenguaje C (bloques) - Transfiere el manejo de threads de las aplicaciones al sistema operativo - Maneja dinámicamente los recursos por nosotros - Disponible desde Snow Leopard y iOS 4 - Apple está migrando a GCD (APIs, Operations, etc) PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO E IVÁN LEIDER
  4. 5.

    Bloques - AKA Closures, Lambda, etc - Función + entorno

    - Aceptan parámetros y devuelven valores - Extensión del lenguaje C/C++/Objective-C - ^{…} - First Class Objects - Se pueden pasar como parámetro - Pueden ser el valor de retorno - Pueden ser retained / released / copied PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO E IVÁN LEIDER
  5. 6.

    Bloques II PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO Y

    IVÁN LEIDER - (NSInteger) add:(NSInteger)param1 to:(NSInteger)param2 { return param1 + param2; } [self add:1 to:2]; Implementación de un método en Objective C
  6. 7.

    Bloques III PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO Y

    IVÁN LEIDER NSInteger add(NSInteger param1, NSInteger param2) { return param1 + param2; } add(1, 2); Implementación de una función en C
  7. 8.

    Bloques IV PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO Y

    IVÁN LEIDER NSInteger (^add)(NSInteger, NSInteger) = ^(NSInteger param1, NSInteger param2) { return param1 + param2; }; add(1, 2); Implementación de un bloque Retorno Bloque Firma (parámetros) Argumentos Cuerpo del bloque
  8. 9.

    Bloques IV PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO Y

    IVÁN LEIDER Implementación de un bloque (con estilo) Retorno Bloque Firma (parámetros) Argumentos Cuerpo del bloque typedef NSInteger(^AddBlock)(NSInteger, NSInteger); AddBlock add = ^(NSInteger param1, NSInteger param2){ return 0; }; add(1,2);
  9. 10.

    Bloques V PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO Y

    IVÁN LEIDER [UIView animateWithDuration:0.2f delay:0.0f options:0 animations:^(void) { self.countdownView.transform = CGAffineTransformMakeScale(4.0f, 4.0f); self.countdownView.alpha = 0.0f; } completion:^(BOOL finished) { [self.countdownView removeFromSuperview]; self.countdownView = nil; [self start]; }]; Bloque inline
  10. 11.

    Bloques VI PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO Y

    IVÁN LEIDER - (void)generateThumbnailWithCompletionHandler:(void (^)(CGImageRef))block { CGImageRef image; // Hacemos los cálculos pertinentes para obtener una imagen // ... block(image); } Bloque como parámetro
  11. 12.

    BLOQUES: scope - Variables locales ~ Objective C - En

    el caso de bloques inline, las variables locales también comprenden las variables definidas en el scope que contiene el bloque (el método en el que es implementado) - No hace falta pasar ningún “contexto” - Los bloques inline pueden escribir en las variables definidas dentro de su scope, pero no en las variables definidas en el método que las contiene. Salvo que estas últimas estén definidas con el modificador __block - También se puede acceder a las propiedades y variables de instancia del objeto dentro el cual fue implementado el bloque PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO E IVÁN LEIDER
  12. 13.

    Bloques: scope II PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO

    E IVÁN LEIDER bool rev = arg; __block int cnt = 0; sort(array, ^(int a, int b) { cnt++; if(rev) return b - a; else return a - b; }); NSLog(@"Count: %d", cnt);
  13. 14.

    gestión de memoria - Ojo! Es muy fácil provocar memory

    leaks/retain cycles - Si accedemos a un objeto, es retenido automáticamente - Excepto si usamos __block - Si accedemos a una variable de instancia, self es retenido - Gestión Pre ARC - Block_copy() / (id)copy; - Block_release() / (void)release; - (id)autorelease - @property (nonatomic, copy) BlockType block; PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO E IVÁN LEIDER
  14. 16.

    RUNTIME ENGINE - Dispatch Queues - Pools of Threads -

    Manejados por GCD a nivel de sistema operativo - Main Queue: ejecuta en el “Main Thread” - Se usa sobre todo para tareas de UI - Concurrent Queues: ejecutan tareas sincronizadas o no sincronizadas - Serial Queues: ejecutan tareas sincronizadas o no sincronizadas como una cola “FIFO” PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO E IVÁN LEIDER
  15. 17.

    API Main Queue PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO

    E IVÁN LEIDER dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_async(mainQueue, ^(void) { [[[UIAlertView alloc] initWithTitle:@"GCD" message:@"GCD is amazing!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; });
  16. 18.

    API II Tareas sincronizadas PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER

    JURADO E IVÁN LEIDER void (^printFrom1To1000)(void) = ^{ for (int i = 1;i <= 1000; i++){ NSLog(@"Counter = %d", i); } }; dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_sync(concurrentQueue, printFrom1To1000); dispatch_sync(concurrentQueue, printFrom1To1000);
  17. 19.

    API III Tareas no sincronizadas PROGRAMACIÓN CONCURRENTE CON GCD -

    XAVIER JURADO E IVÁN LEIDER void (^printFrom1To1000)(void) = ^{ for (int i = 1;i <= 1000; i++){ NSLog(@"Counter = %d", i); } }; dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(concurrentQueue, printFrom1To1000); dispatch_async(concurrentQueue, printFrom1To1000);
  18. 20.

    API IV - Otras APIs - Ejecutar una tarea después

    de un lapso: dispatch_after - Ejecutar una tarea a lo sumo una vez: dispatch_once - Inicialización - True singleton - Ejecutar grupos de tareas: dispatch_group_create, dispatch_group_async, dispatch_group_notify, dispatch_release PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO E IVÁN LEIDER
  19. 21.

    API V Crear Dispatch Queues PROGRAMACIÓN CONCURRENTE CON GCD -

    XAVIER JURADO E IVÁN LEIDER dispatch_queue_t firstSerialQueue = dispatch_queue_create("org.nscoders.serialQueue", 0); dispatch_async(firstSerialQueue, ^{ for (int i = 1;i <= 1000; i++){ NSLog(@"Counter = %d", i); }}); dispatch_async(firstSerialQueue, ^{ for (int i = 1;i <= 1000; i++){ NSLog(@"Counter = %d", i); }});
  20. 22.

    Demo PROGRAMACIÓN CONCURRENTE CON GCD - XAVIER JURADO E IVÁN

    LEIDER https://github.com/NSCoderNightBCN/ GLKitHelloWorld/tree/gcd