Grand Central Dispatch Design Patterns

12,614 views

Published on

Grand Central Dispatch (GCD) and blocks make multi-threading easy. However, there are some lesser-known techniques that benefit your next project.

0 Comments
27 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
12,614
On SlideShare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
210
Comments
0
Likes
27
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Grand Central Dispatch Design Patterns

    1. 1. Grand Central DispatchDesign PatternsBy Robert Brown@robby_brown
    2. 2. Blocks
    3. 3. BlocksBlocks are a proposed addition to C.Like a function pointer, except it also stores the contextthe block was created in.Similar to closures, lambdas, and anonymous functionsin other languages.
    4. 4. BlocksDeclaration Syntax:returnType (^blockName) (Arguments)Blocks may be anonymous.Definition Syntax:^ returnType (Arguments) { code; }The return type and arguments are optional.GCD provides function pointer variants to the block APIs.
    5. 5. BlocksBlocks can modify local variables outside of their scopeif the variables have the new __block keyword.Global and static variables can be modified without the__block keyword.Blocks automatically retain Objective-C objects, exceptobjects that use the __block modifier.C objects must be manually retained.Beware of retain cycles.
    6. 6. Grand Central Dispatch
    7. 7. What is GCD?GCD is a lightweight multithreading engine.Uses a thread pool.Developers create queues of blocks rather thanthreads.Uses lock-less exclusion rather than mutual exclusion.Replaces blocking and polling APIs.
    8. 8. Why Multithread on a SingleCore?Keeps the UI responsive.UI code runs on the main thread.Everything else runs on a background thread.Prevents the main thread from blocking or waiting.
    9. 9. Frequently Used APIsdispatch_async(queue, block);dispatch_once(token, block);dispatch_queue_create(name, type);dispatch_set_target_queue(object, queue);dispatch_get_global_queue(priority, flags);dispatch_release(object);
    10. 10. Global QueuesFour global queues: Main, Low, Default, and High.Only the main thread services the main queue.The three other queues determine the priority ofbackground tasks.Enqueuing is thread safe.
    11. 11. Design Patterns
    12. 12. What is a Design Pattern?After working on related problems, patterns oftenappear in the solutions.Formalized description of best practice.
    13. 13. Initialization Pattern
    14. 14. dispatch_onceGuaranteed to run only once for the lifetime of theapplication.Fast and thread safe.Very easy to use.Great for singletons and static class variables.
    15. 15. The Old Waystatic MyObject * myObject = nil;+ myObject { @synchronized(self) { if (!myObject) myObject = [MyObject new]; } return myObject;}
    16. 16. Problems With@synchronized@synchronized is slow.When synchronizing on the class instance, allother methods that synchronize on it willtemporarily block incoming messages.You can’t synchronize on the class variable since itis initially nil.Using a custom lock also faces the initializationproblem.
    17. 17. The GCD Waystatic MyObject * myObject = nil;+ myObject { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if (!myObject) myObject = [MyObject new]; }); return myObject;}
    18. 18. Lockless Exclusion Pattern
    19. 19. Mutual ExclusionMutual exclusion is classically handled by semaphoresor locks.Both are most efficient when there is no sharingconflicts, (i.e. when you don’t need them) and don’tscale well.Queues are efficient and scale very well.In fact, queues are most efficient under high conflict.
    20. 20. Thread-safe Access// myQueue must be a serial queue NSLock * lock = [NSLock new];dispatch_async(myQueue, ^{ [lock lock]; [self setMySharedVariable:42]; [self setMySharedVariable:42];}); [lock unlock];
    21. 21. Enforcing LocklessExclusion- (NSInteger)mySharedVariable { NSAssert(dispatch_get_current_queue() == myQueue, @“Wrong queue.”); return mySharedVariable; }
    22. 22. Problems with Getters/SettersWe would rather have the compiler write our getters/setters. This technique works well in other methods.Only immutable objects are fully protected this way.
    23. 23. Enforcing LocklessExclusion- (void)accessSharedVariableAsync:(void(^)(id sharedVariable))block { // myQueue must be a serial queue! dispatch_async(myQueue, ^{ block([self sharedVariable]); });}
    24. 24. Enforcing LocklessExclusion- (void)accessSharedVariableSyncSafe:(void(^)(id sharedVariable))block { // myQueue must be a serial queue! if (dispatch_get_current_queue() == myQueue) block([self sharedVariable]); else dispatch_sync(myQueue, ^{ block([self sharedVariable]); });}
    25. 25. Compare to @synchronized[obj accessSharedDataAsync:^(id sharedVar) @synchronized ([obj sharedVar]){ { // Critical code here. // Critical code here.} } Fast - No Locks Slow - Recursive Lock Allows private access Must allow public access Synchronous or Asynchronous Synchronous Only Can be extended to access many shared Only single-value access. data values at once.
    26. 26. Striding Pattern
    27. 27. Why Striding? Myth: My app will go faster if I multithread. Your app will only be faster if the work is parallelizable. Sometimes a block simply contains a loop, and each iteration can be run independently of the others. So, why not spread the iterations across many threads?
    28. 28. One Threaddispatch_async(myQueue, ^{ for(int i = 0; i < 10; i++) [self doIndependentTask:i];});
    29. 29. dispatch_apply// myQueue must be a concurrent queue!dispatch_apply(10, myQueue, ^(size_t idx) { [self doIndependentTask:idx];});
    30. 30. Problems withdispatch_applyOne thread per iteration may be overkill and result inhigh overhead costs.Solution: Use striding (i.e. have one thread run manyiterations). Similar to loop unrolling. You may need to profile your app to find the ideal stride length.
    31. 31. size_t stride = 4;size_t iterations = 10;size_t strideCount = iterations / stride;// myQueue must be a concurrent queue!dispatch_apply(strideCount, myQueue, ^(size_t idx) { size_t i = idx * stride; size_t stop = i + stride; do { [self doIndependentTask:i++]; } while (i < stop);});// Pick up any left over iterations.for (size_t i = strideCount - (strideCount % stride); i < iterations; i++) [self doIndependentTask:i];
    32. 32. Continuation Pattern
    33. 33. What is a Continuation?Well, it’s complicated...take CS 330.Think of it like a completion block wrapped in acompletion block wrapped in a completion block...
    34. 34. Using ContinuationsThe following steps are optional, but either 4 or 5 must bedone. 1. Do some processing. 2. Wrap the completion block in another block. 3. Copy the block if it is going to cross threads (unnecessary with ARC). 4. Pass the completion block to someone else. 5. Execute the completion block.
    35. 35. typedef void(^CHCompletion)(NSError * error);- (void)uploadPhoto:(NSString *)photoPath { // Do some pre-processing. [self processPhotoAtPath:photoPath completion:^(NSError * error) { if (error) dispatch_async(dispatch_get_main_queue(), ^{ // Inform user of error }); }];}
    36. 36. - (void)processPhotoAtPath:(NSString *)path completion:(CHCompletion)completion { [[completion copy] autorelease]; // Do some resizing and add a caption, then save the modified photo to a temporary file for memory efficiency. [self uploadProcessedPhotoAtPath:newPath completion:^(NSError * error) { // Delete the temporary file. if (completion) completion(error); }];}
    37. 37. - (void)uploadProcessedPhotoAtPath:(NSString *)pathcompletion:(CHCompletion)completion { [[completion copy] autorelease]; NSError * error = nil; // Upload the photo. // Set error if something goes wrong. if (completion) completion(error);}
    38. 38. Want to Learn More?WWDC 2011 Session 308 Session 210WWDC 2010 Session 206 Session 211https://github.com/rob-brown/RBCategories/blob/master/GCD+RBExtras.c
    39. 39. Questions?

    ×