Blocks & GCD

32
^{ } and Raphael Sebbe creaceed.com @rsebbe cocoaheads.be blocks

description

Introduction talk about Blocks and Grand Central Dispatch, concurrent programming techniques for Mac and iOS

Transcript of Blocks & GCD

Page 1: Blocks & GCD

^{ } and

Raphael Sebbe [email protected]

blocks

Page 2: Blocks & GCD

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

Page 3: Blocks & GCD

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

Page 4: Blocks & GCD

Overview

• Blocks & GCD are 2 different beasts

• New language feature

• Efficiently define tasks, and execute them

• They complement each other nicely

Page 5: Blocks & GCD

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.

Page 6: Blocks & GCD

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

Page 7: Blocks & GCD

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

Page 8: Blocks & GCD

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

Page 9: Blocks & GCD

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.

Page 10: Blocks & GCD

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

Page 11: Blocks & GCD

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.

Page 12: Blocks & GCD

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

Page 13: Blocks & 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.

Page 14: Blocks & GCD

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

Page 15: Blocks & GCD

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

Page 16: Blocks & GCD

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.)

Page 17: Blocks & GCD
Page 18: Blocks & GCD
Page 19: Blocks & GCD

GCD Concept

• Tasks in Queues

Core

Core

In Out

Q’s are lightweight, have as many as you

want

In Out

Page 20: Blocks & GCD

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

Page 21: Blocks & GCD

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

Page 22: Blocks & GCD

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);

Page 23: Blocks & GCD

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.

Page 24: Blocks & GCD

NSOperationQueue

Core

Core

Page 25: Blocks & GCD

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.

Page 26: Blocks & GCD

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

Page 27: Blocks & GCD

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

Page 28: Blocks & GCD

Xcode Demo’s

• Extending UIAlertView using blocks

• Delving inside Elasty video stabilization method

Page 29: Blocks & GCD
Page 30: Blocks & GCD

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

• ...

Page 31: Blocks & GCD

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

Page 32: Blocks & GCD

Thank you!(Q&A?)