Upload
rsebbe
View
2.659
Download
2
Tags:
Embed Size (px)
DESCRIPTION
Introduction talk about Blocks and Grand Central Dispatch, concurrent programming techniques for Mac and iOS
Citation preview
Ways to Get More
• We can’t get more GHz out of silicon
• Parallelism is the solution
• Nowadays, multi-core systems is the rule
• On it’s way to mobile devices (iPad2)
• Specialized hardware, like GPU, too
• Already there on mobile
SIMD
GPU
Multi-Core
Farms/Cloud
Data-driven Task-driven
Ope
nCL
Gra
nd
Cen
tral
D
ispa
tch
GLS
L
Acc
eler
ate
Load
Ba
lanc
ing
Thr
eads
Cro
n
Ope
nMP
Cor
e Im
age
Overview
• Blocks & GCD are 2 different beasts
• New language feature
• Efficiently define tasks, and execute them
• They complement each other nicely
Blocks• Concept of closure from functional
programming
• Blocks
• are an extension of C language
• store a piece of executable code
• capture the execution context
• are objects (Obj-C or C-based API)
Lisp, Caml, Haskell, Javascript, etc.
Definition of a Block// Simple onevoid (^myblock)() = ^{! printf(“Hello\n”);};myblock();
// With one argvoid (^myblock)(int) = ^(int arg){! printf(“Hello arg=%d\n”, arg);};myblock(1);
// With a return valueint (^myblock)(int) = ^(int arg){! printf(“Hello arg=%d\n”, arg);! return arg + 1;};int r = myblock(1);
~ anonymous function pointer
Typedef’ing a Block// Typedef of a block typetypedef void (^MyBlockType)(NSURL *assetURL, NSError *error);
MyBlockType myBlock = ^(NSURL *assetURL, NSError *error) {! // Some code};
// Syntax of untyped block as Obj-C method argument- (void)addPlayersToMatch:(GKMatch *)match matchRequest:(GKMatchRequest *)matchRequest completionHandler:(void (^)(NSError *))handler
Execution Context (1/3)
int a = 3;
// Context is captured at it’s current statevoid (^myblock)() = ^{! printf(“Hello a=%d\n”, a);};
a = 5;
myblock(); // outputs “Hello a=3”
• Definition of a block captures the execution context
• Variable of standard C types are copied
Execution Context (2/3)
id dict = [[NSDictionary alloc] init];
// Referenced objects are retainedvoid (^myblock)() = ^{! NSLog(“Hello dict=%@\n”, dict);};
[dict release];
myblock(); // outputs “Hello dict=....”
• Captured objects are retained
Remark: For referenced ivar, it’s
self that gets retained. Possible
retain cycles.
Execution Context (3/3)• Shared (R/W) variables with __block
__block int a = 3;
// Context is captured at it’s current statevoid (^myblock)() = ^{! a += 1;! printf(“Hello a=%d\n”, a);};
a = 5;
myblock(); // outputs “Hello a=6”Remark:
__block objects (id, etc.) are not
retained
Block Storage
if (x) {! block = ^{ printf("true\n");};} else {! block = ^{ printf("false\n");};}block(); // unsafe!!!
• When defined, blocks are stack objects, only valid in the definition scope
• Must be copied to heap if used outside of creation context
if (x) {! block = ^{ printf("true\n");}; ! block = [block copy];} else {! block = ^{ printf("false\n");};! block = [block copy];}block(); // safe!!![block release];
Remark: If your method
takes a block as arg., always copy
it.
Blocks Advantages
• Idea: invoke this “block of code” later.
• Callback API are naturally expressed
• Good replacement to your many didEnd: methods
• Task queueing / parallelism much easier
• See GCD
Grand Central Dispatch
• Need for parallelism that scales
• Easy to program for wide adoption
• Parallelism examples
• iTunes - Coverflow, downloads...
• iPhoto - import, uploads, preview
• Twitter Profile Pictures, etc.
Grand Central Dispatch
• Multi-core needs threads
• Say you have a 4-core machine, you need 4 threads for maximum throughput.
• Well... No.
• This is a pre-emptive world
Threads (1/2)
• Optimal number of threads for your app
• Number of (virtual) cores
• Load from other apps
• Thread state (low speed I/O)
• This continuously changes
• Consequences: unused or overused cores
Threads (2/2)
• 3 problems with threads:
• Too low-level, you shouldn’t waste your time at this (when to create/destroy them)
• You generally don’t have easy access to global system info
• Thread programming is hard (sync primitives, etc.)
GCD Concept
• Tasks in Queues
Core
Core
In Out
Q’s are lightweight, have as many as you
want
In Out
Why Q’s• Goal: Best use of cores
• Let the system create/destroy threads for you
• Write less code: wide adoption
• Better overall user experience (responsiveness)
• Technical: Less contention
• Fewer locks
• Scales much better with
• number of tasks
• number of cores
Queue Types
• Serial queues: one task at a time
• User queues
• Main queue
• Concurrent queues: multiple tasks
• 3 priority levels
Serial Q’s are themselves sync
primitives
Only the global one on
10.6 / iOS4
Queuesdispatch_queue_t queue;
// Main (serial) queuequeue = dispatch_get_main_queue();
// User (serial) queuequeue = dispatch_queue_create(“com.mycompany.qname”, ! NULL);
// Global (concurrent) queue, with priorityqueue = dispatch_get_global_queue! (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
Adding Tasks// Synchronous, blocks until code is executeddispatch_sync(queue, ^{! // task code});
dispatch_apply(count, queue, ^(size_t i){! // process ith});
// Asynchronous, returns immediately to callerdispatch_async(queue, ^{! // task code});
dispatch_after(when, queue, ^{! // task code});
API exists for function pointers
too.
NSOperationQueue
Core
Core
Adding Operations// Synchronous, blocks until code is executedNSOperationQueue *queue = [[NSOQ alloc] init];!NSBlockOperation *op1 = [NSBlockOperation ! blockOperationWithBlock:^{! ! // some code! !! }];NSBlockOperation *op2 = [NSBlockOperation ! blockOperationWithBlock:^{! ! // some code!! }];![op2 addDependency:op1];![queue addOperation:op1];[queue addOperation:op2];[queue addOperationWithBlock:^{! // some code! !}];
You can set the max concurrent
ops.
Predates GCD, has some odd APIs. Now built
on top of it.
APIs using Blocks (1/2)// Collections (NSDictionary / NSArray / NSSet)- (void)enumerateKeysAndObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(id key, id obj, BOOL *stop))block
- (NSSet *)keysOfEntriesPassingTest:(BOOL (^)(id key, id obj, BOOL *stop))predicate
- (NSArray *)keysSortedByValueUsingComparator:(NSComparator)cmptr
// NSRegularExpression- (void)enumerateMatchesInString:(NSString *)string options:(NSMatchingOptions)options range:(NSRange)range usingBlock:(void (^)(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop))block
Patterns for collections: enumeration, mutation, tests, comparison
APIs using Blocks (2/2)// ALAssetsLibrary- (void)enumerateGroupsWithTypes:(ALAssetsGroupType)types usingBlock:(ALAssetsLib...ationResultsBlock)enumerationBlock failureBlock:(ALAssetsLib...ssFailureBlock)failureBlock
// Game Kit- (void)loadScoresWithCompletionHandler:(void (^)(NSArray *scores, NSError *error))completionHandler
// AVFoundation, AppKit, many other, etc.
Patterns for accessors: callback / handler
Xcode Demo’s
• Extending UIAlertView using blocks
• Delving inside Elasty video stabilization method
Threads
• Threads are not dead yet, they are just under your feet. (see crashlogs)
• Some uses are well suited at threads
• Real time needs
• OpenGL
• Core Image
• ...
What’s Next?
• Check WWDC videos [210, 308, 322]
• Dispatch group (dispatch_group_*)
• Source (dispatch_source_*)
• Semaphores (dispatch_semaphore_*)
• ARC interactions
• File / Memory I/O
• Target queues
Thank you!(Q&A?)