Grand Central Dispatch
Павел Альбицкий
p.albitsky@gmail.com
Asynchronous execution
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
Submits a block for asynchronous execution on a dispatch queue and returns immediately.
void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
Submits a block object for execution on a dispatch queue and waits until that block completes.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
/* The block to submit to the target dispatch queue. */
});
Running in separate thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
/* Run in background thread */
dispatch_sync(dispatch_get_main_queue(), ^{
/* Run in main thread
Waits until completes */
});
/* Continue in background thread */
});
Queue
Queues
• Serial (private dispatch queues)
Serial queues execute one task at a time in the order in which they are added
to the queue.
• Concurrent (global dispatch queue)
Concurrent queues execute one or more tasks concurrently
• Main dispatch queue
The main dispatch queue is a globally available serial queue that executes
tasks on the application’s main thread
Common queues
• Main queue (serial)
dispatch_get_main_queue() returns the main queue
• Concurrent queues with the specified quality of service class
1. DISPATCH_QUEUE_PRIORITY_HIGH
2. DISPATCH_QUEUE_PRIORITY_DEFAULT
3. DISPATCH_QUEUE_PRIORITY_LOW
4. DISPATCH_QUEUE_PRIORITY_BACKGROUND
dispatch_get_global_queue() returns a system-defined global concurrent
queue
Creating queues
• Concurrent
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.myapp.queue",
DISPATCH_QUEUE_CONCURRENT);
• Serial
dispatch_queue_t serialQueue = dispatch_queue_create("com.myapp.queue",
DISPATCH_QUEUE_SERIAL);
#define DISPATCH_QUEUE_SERIAL NULL
Memory managment
• Before macOS 10.8 or iOS v6.0 – MRC

dispatch_retain(serialQueue);
dispatch_release(serialQueue);
• Later – ARC

Adding tasks to a queue
- (void)gcd {
dispatch_queue_t myCustomQueue;
myCustomQueue = dispatch_queue_create("com.example.MyCustomQueue", NULL);
dispatch_async(myCustomQueue, ^{
printf("Do some work here.n");
});
printf("The first block may or may not have run.n");
dispatch_sync(myCustomQueue, ^{
printf("Do some more work here.n");
});
printf("Both blocks have completed.n");
}
The first block may or may not have run.
Do some work here.
Do some more work here.
Both blocks have completed.
dispatch_once
typedef long dispatch_once_t;
static dispatch_once_t tokenOnce;
dispatch_once(&tokenOnce, ^{
printf("tokenOnce: %ld", tokenOnce);
tokenOnce = 0;
});
tokenOnce: 140734581496400
dispatch_after
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds *
NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^{
//
});
dispatch_time
/*!
* @typedef dispatch_time_t
*
* @abstract
* A somewhat abstract representation of time; where zero means "now" and
* DISPATCH_TIME_FOREVER means "infinity" and every value in between is an
* opaque encoding.
*/
typedef uint64_t dispatch_time_t;
#define DISPATCH_TIME_NOW (0ull)
#define DISPATCH_TIME_FOREVER (~0ull)
dispatch_time_t dispatch_time(dispatch_time_t when, int64_t delta);
Creates a dispatch_time_t relative to the default clock or modifies an existing dispatch_function_t.
• when – The value to use as the basis for a new value
• delta – The number of nanoseconds to add to the time in the when parameter.
Multiple invocations
dispatch_queue_t queue = dispatch_queue_create("com.myapp.queue",
DISPATCH_QUEUE_CONCURRENT);
dispatch_apply(10, queue, ^(size_t index) {
NSLog(@"%@ , %zu",[NSDate date], index);
});
2016-02-16 21:47:38 +0000 , 4
2016-02-16 21:47:38 +0000 , 7
2016-02-16 21:47:38 +0000 , 3
2016-02-16 21:47:38 +0000 , 1
2016-02-16 21:47:38 +0000 , 5
2016-02-16 21:47:38 +0000 , 0
2016-02-16 21:47:38 +0000 , 2
2016-02-16 21:47:38 +0000 , 6
2016-02-16 21:47:38 +0000 , 8
2016-02-16 21:47:38 +0000 , 9
DISPATCH_QUEUE_CONCURRENT -> NULL ?
Parallelize Your for Loops
for (i = 0; i < count; i++) {
results[i] = do_work(data, i);
}
total = summarize(results, count);
dispatch_queue_t queue = dispatch_queue_create("com.myapp.queue",
DISPATCH_QUEUE_CONCURRENT);
dispatch_apply(count, queue, ^(size_t i){
results[i] = do_work(data, i);
});
total = summarize(results, count);
Suspend and resut queue
dispatch_suspend(queue);
dispatch_resume(queue);
Group notify
dispatch_queue_t queue = dispatch_queue_create("com.myapp.queue",
DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^ {
NSLog(@"Block1 Start");
[NSThread sleepForTimeInterval:5.0];
NSLog(@"Block1 End");
});
dispatch_group_async(group, queue, ^ {
NSLog(@"Block2 Start");
[NSThread sleepForTimeInterval:8.0];
NSLog(@"Block2 End");
});
dispatch_group_notify(group, queue, ^ {
NSLog(@"Block3 thread: %@", [NSThread currentThread]);
});
Block2 Start
Block1 Start
Block1 End
Block2 End
Block3 thread: <NSThread: 0x7fe08a10f0a0>{number = 2, name = (null)}
dispatch_group_wait
dispatch_queue_t queue = dispatch_queue_create("com.myapp.queue",
DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^ {
NSLog(@"Block1 Start");
[NSThread sleepForTimeInterval:5.0];
NSLog(@"Block1 End");
});
dispatch_group_async(group, queue, ^ {
NSLog(@"Block2 Start");
[NSThread sleepForTimeInterval:8.0];
NSLog(@"Block2 End");
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"thread: %@", [NSThread currentThread]);
Block2 Start
Block1 Start
Block1 End
Block2 End
Block3 thread: <NSThread: 0x7fa88b502490>{number = 1, name = main}
dispatch_queue_t queue = dispatch_queue_create("com.myapp.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
dispatch_group_t downloadGroup = dispatch_group_create();
for (NSInteger i = 0; i < 3; i++) {
NSURL *url;
switch (i) {
case 0:
url = [NSURL URLWithString:kOverlyAttachedGirlfriendURLString];
break;
case 1:
url = [NSURL URLWithString:kSuccessKidURLString];
break;
}
dispatch_group_enter(downloadGroup);
Photo *photo = [[Photo alloc] initwithURL:url
withCompletionBlock:^(UIImage *image, NSError *_error) {
dispatch_group_leave(downloadGroup);
}];
[[PhotoManager sharedManager] addPhoto:photo];
}
dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER);
dispatch_async(dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock(error);
}
});
});
dispatch_group_enter, dispatch_group_leave
Barrier
dispatch_queue_t queue = dispatch_queue_create("com.myapp.queue”,
DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"Block1 Start");
[NSThread sleepForTimeInterval:3.0];
NSLog(@"Block1 End");
});
dispatch_async(queue, ^{
NSLog(@"Block2 Start");
[NSThread sleepForTimeInterval:2.0];
NSLog(@"Block2 End");
});
dispatch_barrier_async(queue, ^{
NSLog(@"Block3 thread: %@", [NSThread currentThread]);
});
Block2 Start
Block1 Start
Block2 End
Block1 End
Block3 thread: <NSThread: 0x7f8452e1a1d0>{number = 2, name = (null)}
Semaphore
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_queue_t queue = dispatch_queue_create("com.myapp.queue”,
DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue , ^{
NSLog(@"Looooooong opetation....");
[NSThread sleepForTimeInterval:2.0];
NSLog(@"signal");
dispatch_semaphore_signal(sema);
});
NSLog(@"wait for signal");
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
NSLog(@"some shit");
wait for signal
Looooooong opetation....
signal
some shit
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
dispatch_queue_t queue = dispatch_queue_create("com.myapp.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@”Diana is sleeping");
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
NSLog(@“Diana is waking up ;)");
[NSThread sleepForTimeInterval:1.0];
NSLog(@“Diana calls David!");
dispatch_semaphore_signal(sema);
});
dispatch_async(queue, ^{
NSLog(@”David is sleeping");
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
NSLog(@“David is waking up =)");
dispatch_semaphore_signal(sema);
[NSThread sleepForTimeInterval:1.0];
NSLog(@“David calls Diana!");
dispatch_semaphore_signal(sema);
});
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:2.0];
NSLog(@“They are sleeping");
NSLog(@”Nightmare");
dispatch_semaphore_signal(sema);
});
Diana is sleeping
David is sleeping
They are sleeping
Nightmare
Diana is waking up ;)
Diana calls David!
David is waking up =)
David calls Diana!
what happened if dispatch_semaphore_create(1)? Or (-1)?
Спасибо за внимание!
Павел Альбицкий
p.albitsky@gmail.com

Grand Central Dispatch in Objective-C

  • 1.
    Grand Central Dispatch ПавелАльбицкий p.albitsky@gmail.com
  • 2.
    Asynchronous execution void dispatch_async(dispatch_queue_tqueue, dispatch_block_t block); Submits a block for asynchronous execution on a dispatch queue and returns immediately. void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block); Submits a block object for execution on a dispatch queue and waits until that block completes. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ /* The block to submit to the target dispatch queue. */ });
  • 3.
    Running in separatethread dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ /* Run in background thread */ dispatch_sync(dispatch_get_main_queue(), ^{ /* Run in main thread Waits until completes */ }); /* Continue in background thread */ });
  • 4.
  • 5.
    Queues • Serial (privatedispatch queues) Serial queues execute one task at a time in the order in which they are added to the queue. • Concurrent (global dispatch queue) Concurrent queues execute one or more tasks concurrently • Main dispatch queue The main dispatch queue is a globally available serial queue that executes tasks on the application’s main thread
  • 6.
    Common queues • Mainqueue (serial) dispatch_get_main_queue() returns the main queue • Concurrent queues with the specified quality of service class 1. DISPATCH_QUEUE_PRIORITY_HIGH 2. DISPATCH_QUEUE_PRIORITY_DEFAULT 3. DISPATCH_QUEUE_PRIORITY_LOW 4. DISPATCH_QUEUE_PRIORITY_BACKGROUND dispatch_get_global_queue() returns a system-defined global concurrent queue
  • 7.
    Creating queues • Concurrent dispatch_queue_tconcurrentQueue = dispatch_queue_create("com.myapp.queue", DISPATCH_QUEUE_CONCURRENT); • Serial dispatch_queue_t serialQueue = dispatch_queue_create("com.myapp.queue", DISPATCH_QUEUE_SERIAL); #define DISPATCH_QUEUE_SERIAL NULL
  • 8.
    Memory managment • BeforemacOS 10.8 or iOS v6.0 – MRC  dispatch_retain(serialQueue); dispatch_release(serialQueue); • Later – ARC 
  • 9.
    Adding tasks toa queue - (void)gcd { dispatch_queue_t myCustomQueue; myCustomQueue = dispatch_queue_create("com.example.MyCustomQueue", NULL); dispatch_async(myCustomQueue, ^{ printf("Do some work here.n"); }); printf("The first block may or may not have run.n"); dispatch_sync(myCustomQueue, ^{ printf("Do some more work here.n"); }); printf("Both blocks have completed.n"); } The first block may or may not have run. Do some work here. Do some more work here. Both blocks have completed.
  • 10.
    dispatch_once typedef long dispatch_once_t; staticdispatch_once_t tokenOnce; dispatch_once(&tokenOnce, ^{ printf("tokenOnce: %ld", tokenOnce); tokenOnce = 0; }); tokenOnce: 140734581496400
  • 11.
    dispatch_after double delayInSeconds =2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); dispatch_after(popTime, dispatch_get_main_queue(), ^{ // });
  • 12.
    dispatch_time /*! * @typedef dispatch_time_t * *@abstract * A somewhat abstract representation of time; where zero means "now" and * DISPATCH_TIME_FOREVER means "infinity" and every value in between is an * opaque encoding. */ typedef uint64_t dispatch_time_t; #define DISPATCH_TIME_NOW (0ull) #define DISPATCH_TIME_FOREVER (~0ull) dispatch_time_t dispatch_time(dispatch_time_t when, int64_t delta); Creates a dispatch_time_t relative to the default clock or modifies an existing dispatch_function_t. • when – The value to use as the basis for a new value • delta – The number of nanoseconds to add to the time in the when parameter.
  • 13.
    Multiple invocations dispatch_queue_t queue= dispatch_queue_create("com.myapp.queue", DISPATCH_QUEUE_CONCURRENT); dispatch_apply(10, queue, ^(size_t index) { NSLog(@"%@ , %zu",[NSDate date], index); }); 2016-02-16 21:47:38 +0000 , 4 2016-02-16 21:47:38 +0000 , 7 2016-02-16 21:47:38 +0000 , 3 2016-02-16 21:47:38 +0000 , 1 2016-02-16 21:47:38 +0000 , 5 2016-02-16 21:47:38 +0000 , 0 2016-02-16 21:47:38 +0000 , 2 2016-02-16 21:47:38 +0000 , 6 2016-02-16 21:47:38 +0000 , 8 2016-02-16 21:47:38 +0000 , 9 DISPATCH_QUEUE_CONCURRENT -> NULL ?
  • 14.
    Parallelize Your forLoops for (i = 0; i < count; i++) { results[i] = do_work(data, i); } total = summarize(results, count); dispatch_queue_t queue = dispatch_queue_create("com.myapp.queue", DISPATCH_QUEUE_CONCURRENT); dispatch_apply(count, queue, ^(size_t i){ results[i] = do_work(data, i); }); total = summarize(results, count);
  • 15.
    Suspend and resutqueue dispatch_suspend(queue); dispatch_resume(queue);
  • 16.
    Group notify dispatch_queue_t queue= dispatch_queue_create("com.myapp.queue", DISPATCH_QUEUE_CONCURRENT); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue, ^ { NSLog(@"Block1 Start"); [NSThread sleepForTimeInterval:5.0]; NSLog(@"Block1 End"); }); dispatch_group_async(group, queue, ^ { NSLog(@"Block2 Start"); [NSThread sleepForTimeInterval:8.0]; NSLog(@"Block2 End"); }); dispatch_group_notify(group, queue, ^ { NSLog(@"Block3 thread: %@", [NSThread currentThread]); }); Block2 Start Block1 Start Block1 End Block2 End Block3 thread: <NSThread: 0x7fe08a10f0a0>{number = 2, name = (null)}
  • 17.
    dispatch_group_wait dispatch_queue_t queue =dispatch_queue_create("com.myapp.queue", DISPATCH_QUEUE_CONCURRENT); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue, ^ { NSLog(@"Block1 Start"); [NSThread sleepForTimeInterval:5.0]; NSLog(@"Block1 End"); }); dispatch_group_async(group, queue, ^ { NSLog(@"Block2 Start"); [NSThread sleepForTimeInterval:8.0]; NSLog(@"Block2 End"); }); dispatch_group_wait(group, DISPATCH_TIME_FOREVER); NSLog(@"thread: %@", [NSThread currentThread]); Block2 Start Block1 Start Block1 End Block2 End Block3 thread: <NSThread: 0x7fa88b502490>{number = 1, name = main}
  • 18.
    dispatch_queue_t queue =dispatch_queue_create("com.myapp.queue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ dispatch_group_t downloadGroup = dispatch_group_create(); for (NSInteger i = 0; i < 3; i++) { NSURL *url; switch (i) { case 0: url = [NSURL URLWithString:kOverlyAttachedGirlfriendURLString]; break; case 1: url = [NSURL URLWithString:kSuccessKidURLString]; break; } dispatch_group_enter(downloadGroup); Photo *photo = [[Photo alloc] initwithURL:url withCompletionBlock:^(UIImage *image, NSError *_error) { dispatch_group_leave(downloadGroup); }]; [[PhotoManager sharedManager] addPhoto:photo]; } dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER); dispatch_async(dispatch_get_main_queue(), ^{ if (completionBlock) { completionBlock(error); } }); }); dispatch_group_enter, dispatch_group_leave
  • 19.
    Barrier dispatch_queue_t queue =dispatch_queue_create("com.myapp.queue”, DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ NSLog(@"Block1 Start"); [NSThread sleepForTimeInterval:3.0]; NSLog(@"Block1 End"); }); dispatch_async(queue, ^{ NSLog(@"Block2 Start"); [NSThread sleepForTimeInterval:2.0]; NSLog(@"Block2 End"); }); dispatch_barrier_async(queue, ^{ NSLog(@"Block3 thread: %@", [NSThread currentThread]); }); Block2 Start Block1 Start Block2 End Block1 End Block3 thread: <NSThread: 0x7f8452e1a1d0>{number = 2, name = (null)}
  • 20.
    Semaphore dispatch_semaphore_t sema =dispatch_semaphore_create(0); dispatch_queue_t queue = dispatch_queue_create("com.myapp.queue”, DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue , ^{ NSLog(@"Looooooong opetation...."); [NSThread sleepForTimeInterval:2.0]; NSLog(@"signal"); dispatch_semaphore_signal(sema); }); NSLog(@"wait for signal"); dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); NSLog(@"some shit"); wait for signal Looooooong opetation.... signal some shit
  • 21.
    dispatch_semaphore_t sema =dispatch_semaphore_create(0); dispatch_queue_t queue = dispatch_queue_create("com.myapp.queue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ NSLog(@”Diana is sleeping"); dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); NSLog(@“Diana is waking up ;)"); [NSThread sleepForTimeInterval:1.0]; NSLog(@“Diana calls David!"); dispatch_semaphore_signal(sema); }); dispatch_async(queue, ^{ NSLog(@”David is sleeping"); dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); NSLog(@“David is waking up =)"); dispatch_semaphore_signal(sema); [NSThread sleepForTimeInterval:1.0]; NSLog(@“David calls Diana!"); dispatch_semaphore_signal(sema); }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:2.0]; NSLog(@“They are sleeping"); NSLog(@”Nightmare"); dispatch_semaphore_signal(sema); }); Diana is sleeping David is sleeping They are sleeping Nightmare Diana is waking up ;) Diana calls David! David is waking up =) David calls Diana! what happened if dispatch_semaphore_create(1)? Or (-1)?
  • 22.
    Спасибо за внимание! ПавелАльбицкий p.albitsky@gmail.com