Slides de la présentation "TA la découverte de Grand Central Dispatch" de la session des CocoaHeads Rennais du 21 avril 2011. Présentation assurée par Pierre Duchêne et Thomas Dupont, ingénieurs chez Niji
1. A la découverte de
Grand Central Dispatch
Pierre Duchêne
Thomas Dupont
2. Sommaire
• Blocks
➡ Exemples
➡ Syntaxe et utilisation
➡ Gestion mémoire
➡ Bonus
• Grand Central Dispatch
➡ Introduction
➡ libdispatch
➡ API haut niveau
15. Syntaxe et utilisation
Capturer une variable en fait une copie constante
float newAlpha = 1;
[UIView animateWithDuration:0.5 delay:1 options:0
animations:^{ myView.alpha = newAlpha; }
completion:NULL];
newAlpha = 0;
Copie constante
16. Syntaxe et utilisation
Capturer une variable __block garde sa référence
__block int a = 3;
void (^incrementA)(void) = ^{ a++; };
incrementA();
Référence
17. Gestion mémoire
Un Block est créé sur la pile et non sur le tas !
typedef void (^Block)(void);
Block block; int* pInt;
if ( ... ) { if ( ... ) {
block = ^{ ... }; int a = 1;
pInt = &a;
} else { <=> } else {
block = ^{ ... }; int b = 1;
pInt = &b;
} }
block(); // utilisation de pInt
Wrong
18. Gestion mémoire
Copier un Block sur la pile le déplace sur le tas !
typedef void (^Block)(void);
Block block;
if ( ... ) {
block = [[^{ ... } copy] autorelease];
} else {
block = [[^{ ... } copy] autorelease];
}
block();
Right
19. Gestion mémoire
Capturer un objet le retient !
Capturer une variable d’instance retient l’objet auquel elle appartient !
MyClass.h
myObject
MyObject* myObject;
int myIvar;
retain cycle
self Block
MyClass.m
myObject = [[MyObject alloc] initWithBlock:^{
NSLog(@"%i", myIvar);
}];
Wrong
20. Gestion mémoire
Capturer un objet __block ne le retient pas !
MyClass.h
MyObject* myObject;
int myIvar;
MyClass.m
__block MyClass* selfBlock = self;
myObject = [[MyObject alloc] initWithBlock:^{
NSLog(@"%i", selfBlock-> myIvar);
}];
Right
26. Introduction
• Nouveaux éléments de langage (Blocks)
• Une bibliothèque de fonctions (libdispatch)
• Amélioration et simplification de la
gestion de la concurrence
27. Introduction - Pourquoi GCD
• Complexité du multi-threading
• Multiplication des Cores sur toutes les plateformes
• Mauvaise gestion des ressources
28. Introduction - GCD c’est quoi?
• Gestion des threads au niveau du système
• Gestion des problématiques de concurrence
(lock, semaphore...)
29. libdispatch - Queues
• Liste FIFO de Blocks à exécuter
• Ajout de Block FIFO
• Lancement de l’exécution d’un Block FIFO
• Gère les threads qui exécutent les Blocks
30. Queues
• Trois types de Queues :
• Main Queue (Main Thread)
• Private Dispatch Queue (exécution série)
• Global Dispatch Queue (exécution parallèle)
31. Private Dispatch Queue
Current Thread
Block 3
Ajoute Block 1
Block 2
puis Block 2
puis Block 3 Exécute Block 1
Block 1 puis Block 2
puis Block 3
Private
queue Other Thread
32. Global Dispatch Queue
Puis Block 3 sur
Current Thread le premier thread
qui sera libéré
potentiellement
avant la fin
Block 3 du Block 1
Ajoute Block 1
Block 2
puis Block 2
puis Block 2
puis Block 3
Block 1
Lance Block 1
Global
queue Thread Auto Thread Auto
36. libdispatch - étude de cas
• Process en background + mise à jour de l’UI
dispatch_queue_t background_queue;
dispatch_queue_t main_queue;
backgroung_queue = dispatch_queue_create("com.example.myQueue", NULL);
main_queue = dispatch_get_main_queue();
dispatch_async(background_queue, ^{
int result = hardWorkInBackground();
dispatch_async(main_queue, ^{
updateUIWithData(result);
});
});
dispatch_release(background_queue);
37. libdispatch - étude de cas
• Traitement sur les éléments d’un tableau
dispatch_queue_t global_queue;
global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSArray* mySudokuGrid = ...;
dispatch_apply(nb_iteration,global_queue,^(size_t index){
MyCell* cell = [mySudokuGrid objectAtIndex:index];
[cell computeSolutions];
});
38. libdispatch - étude de cas
• Comment remplacer les locks ?
- (void)updateImageCacheWithImage:(UIImage*)img {
NSLock* l = self.cacheLock;
[l lock];
// Section critique, ne pas ajouter deux fois la même image!
if ([self.imageCache containsObj:img]) {
[l unlock]; // Surtout ne pas oublier!
return;
}
[self.imageCache addObj:img];
[l unlock];
}
39. libdispatch - étude de cas
• Simplement par une Queue!
- (void)updateImageCacheWithImage:(UIImage*)img {
dispatch_sync(serial_queue,^{
// Section critique, ne pas ajouter deux fois la même image!
if ([self.imageCache containsObj:img]) {
return;
}
[self.imageCache addObj:img];
});
}
ou mieux : dispatch_async
40. libdispatch - deadlock
• Attention aux deadlock
dispatch_sync(queue, ^{
// Some code
! dispatch_sync(queue, ^{ // Another block });
});
Block 2
!
Block 1
Private
queue Other Thread
41. API haut niveau
• Grand Central Dispatch ajoute à l’existant
• NSOperation
• NSOperationQueue
42. API haut niveau
• NSBlockOperation
• Classe concrête de NSOperation
• Gère l’exécution en parallèle de un ou
plusieurs Blocks
43. API haut niveau
• NSOperationQueue
• C’est elle qui gère l’exécution des opérations
• Peut être configurée
44. API haut niveau - base
• Créer et lancer une opération via NSOperationQueue :
NSOperationQueue* aQueue = [[NSOperationQueue alloc] init];
NSBlockOperation* blockOp = [NSBlockOperation blockOperationWithBlock:^{
// Some Code
}];
[aQueue addOperation:blockOp];
...
[aQueue addOperationWithBlock:^{ // Another Block }];
...
[aQueue release];
45. API haut niveau - dépendance
• Comment indiquer des dépendances entre opérations?
NSBlockOperation* op1 = ...:
NSBlockOperation* op2 = ...:
[op2 addDependencie:op1];
46. API haut niveau - iOS
Sur iOS les NSOperationQueue
! n’utilisent pas Grand Central Dispatch
48. CocoaHeads #1 julien@cocoaheads.fr
http://cocoaheads.fr thomas.dupont@cocoaheads.fr
Traduction automatique et intelligente d’applications Cocoa
Mail : olivier@foodreporter.net
Web : www.foodreporter.fr
GitHub : github.com/AliSoftware
A la découverte de Grand Central Dispatch
Mail : thomas.dupont@niji.fr
Mail : pierre.duchene@niji.fr
Web : www.niji.fr
Partenaire