68
These are confidential sessions—please refrain from streaming, blogging, or taking pictures Session 210 Mastering Grand Central Dispatch Daniel Steffen Core OS 1

210 Mastering Grand Central Dispatch

Embed Size (px)

Citation preview

Page 1: 210 Mastering Grand Central Dispatch

These are confidential sessions—please refrain from streaming, blogging, or taking pictures

Session 210

Mastering Grand Central Dispatch

Daniel SteffenCore OS

1

Page 2: 210 Mastering Grand Central Dispatch

Grand Central Dispatch

• Introduced in Mac OS X Snow Leopard and iOS 4

• Core technology for asynchrony and concurrency

• Identical API and functionality across platforms and hardware

2

Page 3: 210 Mastering Grand Central Dispatch

Grand Central DispatchOverview

• Brief introduction to GCD• What is new in GCD on Mac OS X Lion and iOS 5• Advanced usage of GCD API

3

Page 4: 210 Mastering Grand Central Dispatch

Blocks and QueuesIntroduction to GCD

4

Page 5: 210 Mastering Grand Central Dispatch

^{

}

BlocksEncapsulate units of work

id obj = [Example new];

int arg = 5;

later(

! ! [obj doSomething:arg];

);

arg = 6;

[obj doSomething:arg];

[obj release];

^{

}

5

Page 6: 210 Mastering Grand Central Dispatch

QueuesSerialization

• Lightweight list of blocks• Enqueue and dequeue are FIFO• Serial queues execute blocks one at a time

6

Page 7: 210 Mastering Grand Central Dispatch

QueuesConcurrency

• Concurrent queues execute multiple blocks at the same time• Concurrently executed blocks may complete out of order• Queues execute concurrently with respect to other queues

7

Page 8: 210 Mastering Grand Central Dispatch

Serial Queues

5

^{ … } ^{ … }

^{ … } ^{ … }

Time

^{ … }

8

Page 9: 210 Mastering Grand Central Dispatch

Concurrent Queue

Time

^{ … } ^{ … }^{ … }^{ … } ^{ … }

9

Page 10: 210 Mastering Grand Central Dispatch

QueuesAPI

• Submitting blocks to queuesdispatch_async(queue, ^{ /* Block */ });

dispatch_sync(queue, ^{ /* Block */ });

• Submitting blocks laterdispatch_after(when, queue, ^{ /* Block */ });

• Concurrently executing one block many timesdispatch_apply(iterations, queue, ^(size_t i){ /* Block */ });

dispatch_async

dispatch_sync

dispatch_after

dispatch_apply

10

Page 11: 210 Mastering Grand Central Dispatch

QueuesAPI

• Suspending and resuming executiondispatch_suspend(queue);

dispatch_resume(queue);

• Managing queue lifetimedispatch_retain(queue);

dispatch_release(queue);

dispatch_suspend

dispatch_resume

dispatch_retain

dispatch_release

11

Page 12: 210 Mastering Grand Central Dispatch

QueuesPitfalls

• Intended for flow control, not as general-purpose data structures• Once a block is submitted to a queue, it will execute• Be careful with synchronous API

12

Page 13: 210 Mastering Grand Central Dispatch

QueuesTypes

• Global queuedispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

• Main queuedispatch_get_main_queue();

• Serial queuedispatch_queue_create(“com.company.app.task”, DISPATCH_QUEUE_SERIAL);

dispatch_get_global_queue

dispatch_get_main_queue

dispatch_queue_create

13

Page 14: 210 Mastering Grand Central Dispatch

Concurrent Queues

14

Page 15: 210 Mastering Grand Central Dispatch

Concurrent Queues

• Execute multiple blocks at the same timedispatch_queue_create(“com.company.app.task”, DISPATCH_QUEUE_CONCURRENT);

• Can be suspended and resumed like serial queues• Support barrier blocks

DISPATCH_QUEUE_CONCURRENT

15

Page 16: 210 Mastering Grand Central Dispatch

Concurrent QueuesBarrier Block

• Will not run until all blocks submitted earlier have completed• Blocks submitted later will not run until barrier block has completed• Submitting barrier blocks to concurrent queuesdispatch_barrier_async(concurrent_queue, ^{ /* Barrier */ });

dispatch_barrier_sync(concurrent_queue, ^{ /* Barrier */ });

dispatch_barrier_async

dispatch_barrier_sync

16

Page 17: 210 Mastering Grand Central Dispatch

Concurrent Queue

Time

^{ … }^{ … }^{ … } ^{ … } ^{ … }

17

Page 18: 210 Mastering Grand Central Dispatch

Concurrent QueuesImplement efficient reader/writer schemes

• Many concurrent readers or a single writer (barrier)dispatch_sync(concurrent_queue, ^{ /* Read */ });

dispatch_barrier_async(concurrent_queue, ^{ /* Write */ });

• Readers enqueued while write is in progress• Writer enqueued while reads are in progress

dispatch_sync

dispatch_barrier_async

18

Page 19: 210 Mastering Grand Central Dispatch

Concurrent QueuesImplement efficient reader/writer schemes

- (id)objectAtIndex:(NSUInteger)index {

! ! __block id obj;

! ! dispatch_sync(self.concurrent_queue, ^{

! ! ! obj = [self.array objectAtIndex:index];

! ! });

! ! return obj;

}

- (void)insertObject:(id)obj atIndex:(NSUInteger)index {

! ! dispatch_barrier_async(self.concurrent_queue, ^{

! ! ! [self.array insertObject:obj atIndex:index];

! ! });

}

! ! dispatch_sync

! ! dispatch_barrier_async

! ! ^{

}

! ! ^{

}

19

Page 20: 210 Mastering Grand Central Dispatch

Target Queues

20

Page 21: 210 Mastering Grand Central Dispatch

Target Queues

• Where the dequeue operation for a queue is executed• Global queues are at the bottom of target queue hierarchy• Determine scheduling and dequeue priority

21

Page 22: 210 Mastering Grand Central Dispatch

LowPriorityQueue

HighPriorityQueue

DefaultPriorityQueue

ConcurrentQueue

SerialQueue

BackgroundPriorityQueue

SerialQueue

22

Page 23: 210 Mastering Grand Central Dispatch

Target QueuesBackground priority

• Additional global queue prioritydispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

• Worker threads with lowest scheduling priority• Throttled I/O

DISPATCH_QUEUE_PRIORITY_BACKGROUND

23

Page 24: 210 Mastering Grand Central Dispatch

Target QueuesHierarchy

• Setting target queue is an asynchronous barrier operationdispatch_set_target_queue(queue, target);

• Arbitrarily deep hierarchies are supported• Loops are undefined

dispatch_set_target_queue

24

Page 25: 210 Mastering Grand Central Dispatch

Target QueuesIdioms

• Setting target queue to a serial queue synchronizes with that queue• No implicit ordering between queues

25

Page 26: 210 Mastering Grand Central Dispatch

LowPriorityQueue

HighPriorityQueue

DefaultPriorityQueue

SerialQueue

BackgroundPriorityQueue

ConcurrentQueue

SerialQueue

26

Page 27: 210 Mastering Grand Central Dispatch

Target QueuesMake a concurrent queue serial

• Promote reader-writer lock to exclusive lock• Set target queue to a serial queue• Everything in hierarchy above a serial queue becomes serial

27

Page 28: 210 Mastering Grand Central Dispatch

Serialize callbacks to a caller-supplied queue

• Caller’s queue might be concurrent• Setup serial queue targeting thecaller-supplied queue

• Submit callbacks to this serial queue

ConcurrentQueue

Target Queues

SerialQueue

28

Page 29: 210 Mastering Grand Central Dispatch

Target QueuesJumping the queue

• Enqueueing at the front of a serial queue?• High priority item needs to jump ahead of already enqueued items• Combine queue suspension with target queues

29

Page 30: 210 Mastering Grand Central Dispatch

Target QueuesJumping the queue

low = dispatch_queue_create(“low”, DISPATCH_QUEUE_SERIAL);

high = dispatch_queue_create(“high”, DISPATCH_QUEUE_SERIAL);

dispatch_set_target_queue(low, high);

dispatch_async(low, ^{ /* Low priority block */ });

dispatch_async(low, ^{ /* Low priority block */ });

dispatch_suspend(low);

dispatch_async(high, ^{

! /* High priority block */

! dispatch_resume(low);

});

dispatch_set_target_queue

dispatch_suspend

dispatch_async

dispatch_async

dispatch_resume

dispatch_async

30

Page 31: 210 Mastering Grand Central Dispatch

Jumping the Queue

Time

^{ … } ^{ … } ^{ … } ^{ … }

^{ … }

^{ … } ^{ … } ^{ … } ^{ … }^{ … }

31

Page 32: 210 Mastering Grand Central Dispatch

Queue-Specific Data

32

Page 33: 210 Mastering Grand Central Dispatch

Queue-Specific Data

• Per-queue key-value storagedispatch_queue_set_specific(queue, &key, value, destructor);

value = dispatch_queue_get_specific(queue, &key);

• Keys are compared as pointers• Destructor called when value unset or at queue destruction

dispatch_queue_set_specific

dispatch_queue_get_specific

33

Page 34: 210 Mastering Grand Central Dispatch

Queue-Specific Data

• Current value for keyvalue = dispatch_get_specific(&key);

• Aware of target queue hierarchy■ Value for target queue if current queue has no value set

dispatch_get_specific

34

Page 35: 210 Mastering Grand Central Dispatch

Value 1Value 1

B C

A

Value 2

35

Page 36: 210 Mastering Grand Central Dispatch

Dispatch Data

36

Page 37: 210 Mastering Grand Central Dispatch

Dispatch Data

• Container object for multiple discontiguous memory buffers• Container and represented buffers are immutable• Avoids copying buffers as much as possible

37

Page 38: 210 Mastering Grand Central Dispatch

Creation

• From app-owned bufferdispatch_data_t data = dispatch_data_create(buffer, size,

! ! ! ! ! ! ! ! ! ! ! ! queue, ^{ /* destructor */ });

Dispatch Data

Dispatch Data

Buffer

Dispatch Data

dispatch_data_create

38

Page 39: 210 Mastering Grand Central Dispatch

Destructors

• Copy bufferDISPATCH_DATA_DESTRUCTOR_DEFAULT

• Malloc’d bufferDISPATCH_DATA_DESTRUCTOR_FREE

! " ^{ free(buffer); }

• Custom^{ CFRelease(cfdata); }

Dispatch Data

DISPATCH_DATA_DESTRUCTOR_DEFAULT

DISPATCH_DATA_DESTRUCTOR_FREE

^{ }

39

Page 40: 210 Mastering Grand Central Dispatch

Creation

• Concatenation of data objectsconcat = dispatch_data_create_concat(data1, data2);

Dispatch Data

Data 1 Data 2

dispatch_data_create_concat

Concatenation

40

Page 41: 210 Mastering Grand Central Dispatch

Creation

• Subrange of data objectsubrange = dispatch_data_create_subrange(data, offset, length);

Dispatch Data

dispatch_data_create_subrange

DataSubrange

41

Page 42: 210 Mastering Grand Central Dispatch

Dispatch Data

• Total size of represented bufferssize = dispatch_data_get_size(data);

• Singleton object for zero-sized bufferdispatch_data_t dispatch_data_empty;

dispatch_data_get_size

dispatch_data_empty

42

Page 43: 210 Mastering Grand Central Dispatch

Buffer access

• Copy buffers into single contiguous mapmap = dispatch_data_create_map(data, &buffer, &size);

Dispatch Data

dispatch_data_create_map

DataMap

&buffer &size

43

Page 44: 210 Mastering Grand Central Dispatch

Buffer access

• No copy if buffer is already contiguous map = dispatch_data_create_map(data, &buffer, &size);

Dispatch Data

Data

Map

44

Page 45: 210 Mastering Grand Central Dispatch

Buffer access

• Find contiguous buffer at locationregion = dispatch_data_copy_region(data, location, &offset);

Dispatch Data

dispatch_data_copy_region

DataRegion

45

Page 46: 210 Mastering Grand Central Dispatch

Buffer traversal

• Serially apply a block to each contiguous bufferdispatch_data_apply(data, ^(dispatch_data_t region, size_t offset,

! ! ! ! ! ! ! const void *buffer, size_t size){ /* Iterator */ });

Dispatch Data

^{ … }^

dispatch_data_apply

Data

46

Page 47: 210 Mastering Grand Central Dispatch

Buffer traversal

dispatch_data_t data = acquire_data(), header;

__block size_t position = SIZE_MAX;

dispatch_data_apply(data, ^(dispatch_data_t region, size_t offset,

! ! ! ! ! ! ! ! ! ! const void *buffer, size_t size){

! ! void *location = memchr(buffer, 0x1a, size); /* find ^Z */

! ! if (location) position = offset + (location - buffer);

! ! return (bool)!location;

});

header = dispatch_data_create_subrange(data, 0, position);

dispatch_release(data);

Dispatch Data

__block

dispatch_data_apply region offset

! ! ! ! ! ! ! ! ! ! buffer size

! ! position

! ! (bool)

dispatch_data_create_subrange

dispatch_release

47

Page 48: 210 Mastering Grand Central Dispatch

Dispatch I/O

48

Page 49: 210 Mastering Grand Central Dispatch

Dispatch I/OGoals

• Asynchronous I/O from file descriptors and paths• Extend GCD patterns to POSIX-level file and network I/O• Optimize I/O process-wide across subsystems

49

Page 50: 210 Mastering Grand Central Dispatch

Dispatch I/OOptimizations

• Non-blocking network I/O• Concurrent I/O to different physical devices• Pipelining of I/O requests to single device

50

Page 51: 210 Mastering Grand Central Dispatch

Dispatch I/OOptimized throughput with advisory reads

4k 32k 256k 2048k 16384k

Thro

ughp

ut

Filesize

Dispatch I/Oread()

iPad 2 (16 GB) reading 640 files

51

Page 52: 210 Mastering Grand Central Dispatch

Dispatch I/OAdvantages

• Avoid threads blocked in I/O syscalls• Manage I/O buffers with dispatch data objects• Incremental processing of partial data

52

Page 53: 210 Mastering Grand Central Dispatch

Dispatch I/OChannels

• Encapsulate I/O policy on file descriptor or path• Track file descriptor ownership • Specify access type at creationDISPATCH_IO_STREAM

DISPATCH_IO_RANDOM

DISPATCH_IO_STREAM

DISPATCH_IO_RANDOM

53

Page 54: 210 Mastering Grand Central Dispatch

Dispatch I/OStream-access channels

• I/O operations start at (and advance) file pointer position• Asynchronous I/O operations are performed serially• Reads may be performed concurrently with writes

54

Page 55: 210 Mastering Grand Central Dispatch

Dispatch I/ORandom-access channels

• I/O operations start at specified offset to initial file pointer position• Asynchronous I/O operations are performed concurrently• File descriptor must be seekable

55

Page 56: 210 Mastering Grand Central Dispatch

Dispatch I/OChannel creation

• With file descriptordispatch_io_create(type, fd, queue, ^(…){ /* Cleanup */ });

• With pathdispatch_io_create_with_path(type, path, oflag, mode, queue,

! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ^(…){ /* Cleanup */ });

• With channeldispatch_io_create_with_io(type, channel, queue, ^(…){ /* Cleanup */ });

dispatch_io_create

dispatch_io_create_with_path

dispatch_io_create_with_io

56

Page 57: 210 Mastering Grand Central Dispatch

Dispatch I/OChannel cleanup

• File descriptor is under system control until cleanup handler is called■ Must not modify file descriptor directly during this time

• Occurs once all pending I/O operations have completed andchannel has been released or closed^(int error){

! ! if (error) { /* Handle error */ }

! ! close(fd);

}

^(int error){

}

57

Page 58: 210 Mastering Grand Central Dispatch

Dispatch I/OI/O operations

• Asynchronous read at file pointer or offsetdispatch_io_read(channel, offset, length, queue, ^(…){ /* Handler */ });

• Asynchronous write at file pointer or offsetdispatch_io_write(channel, offset, data, queue, ^(…){ /* Handler */ });

dispatch_io_read

dispatch_io_write

58

Page 59: 210 Mastering Grand Central Dispatch

Dispatch I/OI/O handlers

• Incremental processing■ Must retain data if needed after handler returns

• Read operations are passed data read since last handler invocation• Write operations are passed data not yet written^(bool done, dispatch_data_t data, int error){

! ! if (data) { /* Process partial data */ }

! ! if (error) { /* Handle error */ }

! ! if (done) { /* Complete processing */ }

}

^(bool done, dispatch_data_t data, int error){

}

59

Page 60: 210 Mastering Grand Central Dispatch

Dispatch I/OBarrier operations

• Executes once pending I/O operations have completed• Exclusive access to file descriptor• Non-destructive modifications of file descriptor alloweddispatch_io_barrier(channel, ^{

! ! int fd = dispatch_io_get_descriptor(channel);

! ! if (fsync(fd) == -1) {

! ! ! handle_error(errno);

! ! }

});

! ! dispatch_io_get_descriptor

fsync

dispatch_io_barrier ^{

}

60

Page 61: 210 Mastering Grand Central Dispatch

Dispatch I/OClosing channels

• Close to new operations but let existing operations completedispatch_io_close(channel, 0);

• Close and interrupt existing operationsdispatch_io_close(channel, DISPATCH_IO_STOP);

dispatch_io_close

DISPATCH_IO_STOP

61

Page 62: 210 Mastering Grand Central Dispatch

Dispatch I/OTransliteration

dispatch_io_t in, out;

dispatch_queue_t q = dispatch_get_global_queue(

! ! ! ! ! ! ! ! ! DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

in = dispatch_io_create(DISPATCH_IO_RANDOM, fd, q, ^(int err){

! ! if (err) handle_error(err);

! ! close(fd);

});

out = dispatch_io_create_with_path(DISPATCH_IO_STREAM,

! ! ! ! path, O_WRONLY|O_CREAT, 0600, q, ^(int err){

! ! if (err) handle_error(err);

});

dispatch_io_create DISPATCH_IO_RANDOM fd

dispatch_io_create_with_path DISPATCH_IO_STREAM

! ! ! ! path O_WRONLY|O_CREAT 0600

62

Page 63: 210 Mastering Grand Central Dispatch

Dispatch I/OTransliteration

dispatch_io_read(in, 0, SIZE_MAX, q,

! ! ! ! ^(bool done, dispatch_data_t data, int err){

! ! if (data) {

! ! ! dispatch_data_t tdata = transliterate(data);

! ! ! dispatch_io_write(out, 0, tdata, q,

! ! ! ! ! ! ^(bool wdone, dispatch_data_t wdata, int werr){

! ! ! ! if (werr) handle_error(werr); });

! ! ! dispatch_release(tdata);

! ! }

! ! if (done) dispatch_release(out);

! ! if (err) handle_error(err); });

dispatch_release(in);

dispatch_io_read in 0 SIZE_MAX

! ! ! ! done data err

! ! ! transliterate

! ! ! dispatch_io_write out 0 tdata

! ! ! dispatch_release

! ! dispatch_release

dispatch_release

63

Page 64: 210 Mastering Grand Central Dispatch

Summary

• Target queues• Concurrent queues• Queue-specific data• Dispatch data• Dispatch I/O

64

Page 65: 210 Mastering Grand Central Dispatch

More Information

Michael JurewitzDeveloper Tools and Performance [email protected]

DocumentationConcurrency Programming Guidehttp://developer.apple.com

Open SourceMac OS Forge > libdispatchhttp://libdispatch.macosforge.org

Apple Developer Forumshttp://devforums.apple.com

65

Page 66: 210 Mastering Grand Central Dispatch

Blocks and Grand Central Dispatch in Practice Pacific HeightsWednesday 10:15AM

Introducing XPC Russian HillWednesday 11:30AM

Related Sessions

Introducing Blocks and Grand Central Dispatch on iPhone WWDC10iTunes

Simplifying iPhone App Development with Grand Central Dispatch WWDC10iTunes

66

Page 67: 210 Mastering Grand Central Dispatch

Grand Central Dispatch Lab CoreOS Lab AThursday 2:00PM - 3:45PM

Labs

67

Page 68: 210 Mastering Grand Central Dispatch

68