Question

In Grand Central Dispatch, how does the dispatcher work with different queues (serial and concurrent) when using the dispatch_sync function and the dispatch_async function?

Was it helpful?

Solution

First of all we need two type of queue: one serial and one concurrent:

dispatch_queue_t serialQueue =
dispatch_queue_create("com.matteogobbi.dispex.serial_queue", DISPATCH_QUEUE_SERIAL);

dispatch_queue_t concurrentQueue =
dispatch_queue_create("com.matteogobbi.dispex.concurrent_queue", DISPATCH_QUEUE_CONCURRENT);

So, we can start with the first experiment, using a serial queue and all dispatch_async function to add our block to the queue:

/* Dispatch async with serial queue */
NSLog(@"\n\nDISPATCH: Async - QUEUE: Serial");

NSLog(@"block 1 added");
dispatch_async(serialQueue, ^{
    NSLog(@"block 1");
});

NSLog(@"block 2 added");
dispatch_async(serialQueue, ^{
    NSLog(@"block 2");
});

NSLog(@"block 3 added");
dispatch_async(serialQueue, ^{
    NSLog(@"block 3");
});

NSLog(@"block 4 added");
dispatch_async(serialQueue, ^{
    NSLog(@"block 4");
});

NSLog(@"block 5 added");
dispatch_async(serialQueue, ^{
    NSLog(@"block 5");
});

NSLog(@"block 6 added");
dispatch_async(serialQueue, ^{
    NSLog(@"block 6");
});

NSLog(@"block 7 added");
dispatch_async(serialQueue, ^{
    NSLog(@"block 7");
});

NSLog(@"block 8 added");
dispatch_async(serialQueue, ^{
    NSLog(@"block 8");
});

NSLog(@"block 9 added");
dispatch_async(serialQueue, ^{
    NSLog(@"block 9");
});

NSLog(@"block 10 added");
dispatch_async(serialQueue, ^{
    NSLog(@"block 10");
});

NSLog(@"ALL BLOCK ADDED TO THE QUEUE --> FUNCTION RETURNED");

DISPATCH: Async - QUEUE: Serial

2014-04-08 14:43:16.468 dispex[4346:60b] block 1 added

2014-04-08 14:43:16.468 dispex[4346:60b] block 2 added

2014-04-08 14:43:16.468 dispex[4346:1303] block 1

2014-04-08 14:43:16.469 dispex[4346:1303] block 2

2014-04-08 14:43:16.468 dispex[4346:60b] block 3 added

2014-04-08 14:43:16.469 dispex[4346:1303] block 3

2014-04-08 14:43:16.469 dispex[4346:60b] block 4 added

2014-04-08 14:43:16.469 dispex[4346:1303] block 4

2014-04-08 14:43:16.469 dispex[4346:60b] block 5 added

2014-04-08 14:43:16.470 dispex[4346:60b] block 6 added

2014-04-08 14:43:16.470 dispex[4346:1303] block 5

2014-04-08 14:43:16.471 dispex[4346:60b] block 7 added

2014-04-08 14:43:16.471 dispex[4346:1303] block 6

2014-04-08 14:43:16.471 dispex[4346:1303] block 7

2014-04-08 14:43:16.471 dispex[4346:60b] block 8 added

2014-04-08 14:43:16.471 dispex[4346:1303] block 8

2014-04-08 14:43:16.471 dispex[4346:60b] block 9 added

2014-04-08 14:43:16.472 dispex[4346:60b] block 10 added

2014-04-08 14:43:16.472 dispex[4346:1303] block 9

2014-04-08 14:43:16.472 dispex[4346:1303] block 10

2014-04-08 14:43:16.472 dispex[4346:60b] ALL BLOCK ADDED TO THE QUEUE --> FUNCTION RETURNED

As you can see, the block are added to the queue but in the meantime the dispatcher begin to execute them. This is a characteristic of the dispatcher_async function, that is add block to the queue without wait that them finish to be executed. In other words, if you are using dispatch_async in a function, the function return immediately and in the meantime the block is executing. This is extremely useful! In this example i used NSLog to report when the block are added to the queue and so this does to be the execution slower and causes the log

ALL BLOCK ADDED

at the end. But as we will see after, without logs it will be wrote at the beginning. Due the fact that we are using a serial queue, the block are executed in the order of adding.

Next:

/* Just wait before begin with the next test */
dispatch_group_wait(group_async_serial, DISPATCH_TIME_FOREVER);


/* Dispatch sync with serial queue */
NSLog(@"\n\nDISPATCH: Sync - QUEUE: Serial");

NSLog(@"block 1 added");
dispatch_sync(serialQueue, ^{
    NSLog(@"block 1");
});

NSLog(@"block 2 added");
dispatch_sync(serialQueue, ^{
    NSLog(@"block 2");
});

NSLog(@"block 3 added");
dispatch_sync(serialQueue, ^{
    NSLog(@"block 3");
});

NSLog(@"block 4 added");
dispatch_sync(serialQueue, ^{
    NSLog(@"block 4");
});

NSLog(@"block 5 added");
dispatch_sync(serialQueue, ^{
    NSLog(@"block 5");
});

NSLog(@"block 6 added");
dispatch_sync(serialQueue, ^{
    NSLog(@"block 6");
});

NSLog(@"block 7 added");
dispatch_sync(serialQueue, ^{
    NSLog(@"block 7");
});

NSLog(@"block 8 added");
dispatch_sync(serialQueue, ^{
    NSLog(@"block 8");
});

NSLog(@"block 9 added");
dispatch_sync(serialQueue, ^{
    NSLog(@"block 9");
});

NSLog(@"block 10 added");
dispatch_sync(serialQueue, ^{
    NSLog(@"block 10");
});

NSLog(@"ALL BLOCK ADDED TO THE QUEUE --> FUNCTION RETURNED");

DISPATCH: Sync - QUEUE: Serial

2014-04-08 14:43:16.473 dispex[4346:60b] block 1 added

2014-04-08 14:43:16.474 dispex[4346:60b] block 1

2014-04-08 14:43:16.474 dispex[4346:60b] block 2 added

2014-04-08 14:43:16.474 dispex[4346:60b] block 2

2014-04-08 14:43:16.475 dispex[4346:60b] block 3 added

2014-04-08 14:43:16.475 dispex[4346:60b] block 3

2014-04-08 14:43:16.475 dispex[4346:60b] block 4 added

2014-04-08 14:43:16.475 dispex[4346:60b] block 4

2014-04-08 14:43:16.476 dispex[4346:60b] block 5 added

2014-04-08 14:43:16.476 dispex[4346:60b] block 5

2014-04-08 14:43:16.476 dispex[4346:60b] block 6 added

2014-04-08 14:43:16.477 dispex[4346:60b] block 6

2014-04-08 14:43:16.477 dispex[4346:60b] block 7 added

2014-04-08 14:43:16.477 dispex[4346:60b] block 7

2014-04-08 14:43:16.477 dispex[4346:60b] block 8 added

2014-04-08 14:43:16.478 dispex[4346:60b] block 8

2014-04-08 14:43:16.478 dispex[4346:60b] block 9 added

2014-04-08 14:43:16.478 dispex[4346:60b] block 9

2014-04-08 14:43:16.479 dispex[4346:60b] block 10 added

2014-04-08 14:43:16.479 dispex[4346:60b] block 10

2014-04-08 14:43:16.479 dispex[4346:60b] ALL BLOCK ADDED TO THE QUEUE --> FUNCTION RETURNED

In this example we are using dispatch_sync function with a serial queue. It's very easy to see that all block are added when the previous block finish to be executed. This is a characteristic of dispatch_sync. In other words the function doesn't return until the block finish to be executed. Due the fact that is a serial queue, the order also here is respected.

Next:

/* Dispatch async with concurrent queue */
NSLog(@"\n\nDISPATCH: Async - QUEUE: Concurrent");
dispatch_group_t group_async_concurrent = dispatch_group_create();

dispatch_group_async(group_async_concurrent, concurrentQueue, ^{
    NSLog(@"block 1");
});

dispatch_group_async(group_async_concurrent, concurrentQueue, ^{
    NSLog(@"block 2");
});

dispatch_group_async(group_async_concurrent, concurrentQueue, ^{
    NSLog(@"block 3");
});

dispatch_group_async(group_async_concurrent, concurrentQueue, ^{
    NSLog(@"block 4");
});

dispatch_group_async(group_async_concurrent, concurrentQueue, ^{
    NSLog(@"block 5");
});

dispatch_group_async(group_async_concurrent, concurrentQueue, ^{
    NSLog(@"block 6");
});

dispatch_group_async(group_async_concurrent, concurrentQueue, ^{
    NSLog(@"block 7");
});

dispatch_group_async(group_async_concurrent, concurrentQueue, ^{
    NSLog(@"block 8");
});

dispatch_group_async(group_async_concurrent, concurrentQueue, ^{
    NSLog(@"block 9");
});

dispatch_group_async(group_async_concurrent, concurrentQueue, ^{
    NSLog(@"block 10");
});

dispatch_group_async(group_async_concurrent, concurrentQueue, ^{
    NSLog(@"block 11");
});

dispatch_group_async(group_async_concurrent, concurrentQueue, ^{
    NSLog(@"block 12");
});

dispatch_group_async(group_async_concurrent, concurrentQueue, ^{
    NSLog(@"block 13");
});

dispatch_group_async(group_async_concurrent, concurrentQueue, ^{
    NSLog(@"block 14");
});

NSLog(@"ALL BLOCK ADDED TO THE QUEUE --> FUNCTION RETURNED");

DISPATCH: Async - QUEUE: Concurrent

2014-04-08 14:43:16.480 dispex[4346:60b] ALL BLOCK ADDED TO THE QUEUE --> FUNCTION RETURNED

2014-04-08 14:43:16.480 dispex[4346:1303] block 1

2014-04-08 14:43:16.480 dispex[4346:3503] block 2

2014-04-08 14:43:16.480 dispex[4346:3603] block 3

2014-04-08 14:43:16.480 dispex[4346:3803] block 5

2014-04-08 14:43:16.480 dispex[4346:3703] block 4

2014-04-08 14:43:16.480 dispex[4346:3903] block 6

2014-04-08 14:43:16.480 dispex[4346:3a03] block 7

2014-04-08 14:43:16.480 dispex[4346:3b03] block 8

2014-04-08 14:43:16.482 dispex[4346:1303] block 9

2014-04-08 14:43:16.483 dispex[4346:3503] block 10

2014-04-08 14:43:16.483 dispex[4346:3803] block 12

2014-04-08 14:43:16.483 dispex[4346:3703] block 13

2014-04-08 14:43:16.483 dispex[4346:3903] block 14

2014-04-08 14:43:16.483 dispex[4346:3603] block 11

As i said before, here i show how work dispatch_async but with a concurrent queue. It's really interesting because without NSLog to show when the block is added, you can see how ALL BLOCKS are added before that the first block is executed. This behaviour is not constant. Can happen that block1 is executed and immediately after the dispatch_async finish to add all blocks to the queue and then continue to execute other blocks. Another thing to note, is that the block are executed concurrently, and so them doesn't respect the order of adding and also this behaviour is not constant but depend from the CPU usage, performance and many other things.

Next:

/* Just wait before begin with the next test */
dispatch_group_wait(group_async_concurrent, DISPATCH_TIME_FOREVER);


/* Dispatch sync with concurrent queue */
NSLog(@"\n\nDISPATCH: Sync - QUEUE: Concurrent");

NSLog(@"block 1 added");
dispatch_sync(concurrentQueue, ^{
    NSLog(@"block 1");
});

NSLog(@"block 2 added");
dispatch_sync(concurrentQueue, ^{
    NSLog(@"block 2");
});

NSLog(@"block 3 added");
dispatch_sync(concurrentQueue, ^{
    NSLog(@"block 3");
});

NSLog(@"block 4 added");
dispatch_sync(concurrentQueue, ^{
    NSLog(@"block 4");
});

NSLog(@"block 5 added");
dispatch_sync(concurrentQueue, ^{
    NSLog(@"block 5");
});

NSLog(@"block 6 added");
dispatch_sync(concurrentQueue, ^{
    NSLog(@"block 6");
});

NSLog(@"block 7 added");
dispatch_sync(concurrentQueue, ^{
    NSLog(@"block 7");
});

NSLog(@"block 8 added");
dispatch_sync(concurrentQueue, ^{
    NSLog(@"block 8");
});

NSLog(@"block 9 added");
dispatch_sync(concurrentQueue, ^{
    NSLog(@"block 9");
});

NSLog(@"block 10 added");
dispatch_sync(concurrentQueue, ^{
    NSLog(@"block 10");
});

NSLog(@"ALL BLOCK ADDED TO THE QUEUE --> FUNCTION RETURNED");

DISPATCH: Sync - QUEUE: Concurrent

2014-04-08 14:43:16.486 dispex[4346:60b] block 1 added

2014-04-08 14:43:16.486 dispex[4346:60b] block 1

2014-04-08 14:43:16.487 dispex[4346:60b] block 2 added

2014-04-08 14:43:16.487 dispex[4346:60b] block 2

2014-04-08 14:43:16.487 dispex[4346:60b] block 3 added

2014-04-08 14:43:16.488 dispex[4346:60b] block 3

2014-04-08 14:43:16.488 dispex[4346:60b] block 4 added

2014-04-08 14:43:16.488 dispex[4346:60b] block 4

2014-04-08 14:43:16.489 dispex[4346:60b] block 5 added

2014-04-08 14:43:16.489 dispex[4346:60b] block 5

2014-04-08 14:43:16.489 dispex[4346:60b] block 6 added

2014-04-08 14:43:16.489 dispex[4346:60b] block 6

2014-04-08 14:43:16.490 dispex[4346:60b] block 7 added

2014-04-08 14:43:16.490 dispex[4346:60b] block 7

2014-04-08 14:43:16.490 dispex[4346:60b] block 8 added

2014-04-08 14:43:16.491 dispex[4346:60b] block 8

2014-04-08 14:43:16.491 dispex[4346:60b] block 9 added

2014-04-08 14:43:16.491 dispex[4346:60b] block 9

2014-04-08 14:43:16.492 dispex[4346:60b] block 10 added

2014-04-08 14:43:16.492 dispex[4346:60b] block 10

2014-04-08 14:43:16.492 dispex[4346:60b] ALL BLOCK ADDED TO THE QUEUE --> FUNCTION RETURNED

Finally, here we used dispatch_sync with concurrent queue. It seems perfectly equal to the couple sync/serial. In this case is so. This behaviour is due the fact that also if the queue is concurrent, it haven't got other block to execute because we are using the synchronous dispatcher and so, it wait to add the next block until the actual doesn't finish to be executed. This type of couple (sync/concurrent) is useful if we are also adding to the queue, blocks with dispatch_async. In that case the dispatcher could have other blocks added to the queue to be executed.

Hope that this mini demonstration has been useful ;)

Cheers!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top