Grand Central Dispatch (GCD) is a relatively new solution to multi-core programming developed by Apple. It is primarily used to optimize applications to support multicore processors and other symmetric multiprocessing systems. It is a parallel task based on thread pool mode, used after ios4

Advantages of using GCD

  1. GCD can be used for parallel computing with multiple cores (this makes better use of the advantages of multiple cores)
  2. GCD automatically takes advantage of scheduling more CPU cores
  3. GCD automatically manages the life cycle of threads (creation, task scheduling, thread destruction)
  4. You only need to write business logic and you don’t need to write thread management code

2. Tasks and queues

  • ** tasks :** tasks are things that are placed in threads to be executed, things that need to be executed in GCD blocks,
  • Tasks can be executed synchronously or asynchronously. The difference lies in the ability to start threads
  • ** Sync :** can only perform tasks in the current thread and does not have the ability to start a thread
  • ** Async :** Can execute tasks in a new thread, with the ability to start a new thread

Queue: The queue here refers to the task queue, which is used to store tasks. A queue is a special linear table that uses FIFO (first in, first out), meaning that new tasks are always inserted at the end of the queue and read from the head of the queue. Each time a task is read, a task is released from the queue. There are two types of queues in GCD: serial queues and parallel queues

  • Concurrent queue: Allows multiple tasks to execute in parallel
  • The parallel function is only valid for asynchronous (dispatch_async) functions
  • Serial A queue in which tasks are executed sequentially

3. Use of GCD There are two steps to use GCD

  1. Create a queue (serial queue and parallel queue)

  2. Add the task to the queue

1. Create a queue

  • Create an object with dispatch_queue_CREATE and pass in two parameters. The first parameter is the unique identifier of the queue, which can be null, and the second parameter identifies the queue type **(Serial queue Serial parallel queue Concurrent)**
Dispatch_queue_t queue= dispatch_queue_create("queueSerial", DISPATCH_QUEUE_SERIAL); Dispatch_queue_t queue= dispatch_queue_create("queueConcurrent", DISPATCH_QUEUE_CONCURRENT);Copy the code
  • Parallel queues can be created using dispatch_get_global_queue. By default, global parallel queues are provided. You need to pass in two parameters: “DISPATCH_QUEUE_PRIORITY_DEFAULT”, “0” or “0”

2. Create a task

Dispatch_sync (queue, ^{NSLog(@"%@",[NSThread currentThread]); }); Dispatch_async (queue, ^{NSLog(@"%@",[NSThread currentThread]); });Copy the code

Above is the simple creation of queues and tasks, which in practice we mostly use in combination

  • Parallel synchronous execution
  • Parallel asynchronous execution
  • Serial synchronous execution
  • Serial asynchronous execution

Let’s look at the implementation

1. Parallel and synchronous execution

dispatch_queue_t concurrentQueue = dispatch_queue_create("ConCurrent", DISPATCH_QUEUE_CONCURRENT); NSLog(@"======= start execution "); ConcurrentQueue ^{for (int I = 0; i < 3; i++) { NSLog(@"1----%@",[NSThread currentThread]); } dispatch_sync(concurrentQueue, ^{ for (int i = 0; i < 3; i++) { NSLog(@"2----%@",[NSThread currentThread]); }}); }); NSLog(@"======= end of execution ");Copy the code

Take a look at the output As you can see from the picture, the tasks are performed sequentially,

2. Perform asynchronous execution in parallel

dispatch_queue_t concurrentQueue = dispatch_queue_create("ConCurrent", DISPATCH_QUEUE_CONCURRENT); NSLog(@"======= start execution "); // dispatch_async(concurrentQueue, ^{for (int I = 0; i < 3; i++) { NSLog(@"1----%@",[NSThread currentThread]); }}); dispatch_async(concurrentQueue, ^{ for (int i = 0; i < 3; i++) { NSLog(@"2----%@",[NSThread currentThread]); }}); NSLog(@"======= end of execution ");Copy the code

The execution result shows that the task is added to the thread queue before execution, and task 3 is executed in alternate order. Serial synchronous execution

  • No new thread will be started. The task will be executed in the current thread. The task will be executed sequentially, after completing one task, the next task will be executed
// SerialQueue = dispatch_queue_create("SerialCurrent", DISPATCH_QUEUE_SERIAL); NSLog(@"======= start execution "); dispatch_sync(SerialQueue, ^{ for (int i = 0; i < 3; i++) { NSLog(@"1----%@",[NSThread currentThread]); }}); dispatch_sync(SerialQueue, ^{ for (int i = 0; i < 3; i++) { NSLog(@"2----%@",[NSThread currentThread]); }}); NSLog(@"======= end of execution ");Copy the code

Tasks are executed sequentially, between start and end, which means that tasks are executed immediately after they are added to the queue and feel the same as parallel synchronous execution

4. Perform serial asynchronous execution

  • It starts a thread and it starts a new thread, but it’s a serial queue, so it’s sequential, and it doesn’t finish until it finishes the next task
dispatch_queue_t SerialQueue = dispatch_queue_create("SerialCurrent", DISPATCH_QUEUE_SERIAL); NSLog(@"======= start execution "); dispatch_async(SerialQueue, ^{ for (int i = 0; i < 3; i++) { NSLog(@"1----%@",[NSThread currentThread]); }}); dispatch_async(SerialQueue, ^{ for (int i = 0; i < 3; i++) { NSLog(@"2----%@",[NSThread currentThread]); }}); NSLog(@"======= end of execution ");Copy the code

###### From the printed result, tasks are added to the queue before execution, because it is a serial queue, so the program is executed sequentially.

One of the important functions of GCD is to use (dispatch_group_notify). In the actual development, we need to use (dispatch_group_notify) for the execution of multiple tasks

Dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue, ^{ for (int i = 0; i < 3; I++) {NSLog(@" task 1 "); }}); dispatch_group_async(group, queue, ^{ for (int i = 0; i < 3; I++) {NSLog(@" task two "); }}); dispatch_group_async(group, queue, ^{ for (int i = 0; i < 3; I++) {NSLog(@" task three "); }}); Dispatch_group_notify (dispatch_get_main_queue(), ^{NSLog(@" task completed "); });Copy the code

###### You can view the task execution resultdispatch_get_global_queueIs a parallel queue (globally parallel queue) Notify is executed after all other tasks have been executed

4. Another important function in GCD is dispatch_barrier_async

It is literally a fence, like a wall, separating the top from the bottom. The development scenario is that the thread added to the queue completes the execution of the other thread added to the queue

dispatch_queue_t barriQueue = dispatch_queue_create("barri", DISPATCH_QUEUE_CONCURRENT); NSLog(@"======= start execution "); dispatch_async(barriQueue, ^{ for (int i = 0; i < 3; i++) { NSLog(@"1----%@",[NSThread currentThread]); }}); dispatch_async(barriQueue, ^{ for (int i = 0; i < 3; i++) { NSLog(@"2----%@",[NSThread currentThread]); }}); dispatch_barrier_async(barriQueue, ^{ NSLog(@"barri =====%@",[NSThread currentThread]); }); dispatch_async(barriQueue, ^{ for (int i = 0; i < 3; i++) { NSLog(@"4----%@",[NSThread currentThread]); }}); dispatch_async(barriQueue, ^{ for (int i = 0; i < 3; i++) { NSLog(@"5----%@",[NSThread currentThread]); }}); NSLog(@"======= end of execution "); }Copy the code
2017-11-02 11:38:37.035 TestApp[6549:670187] ======= Start 2017-11-02 11:38:37.036 TestApp[6549:670187] ======= No further action is required The 2017-11-02 11:38:37. 036 TestApp [6549-670603] 2 - < NSThread: 0x60000006AA80 >{Number = 4, name = (null)} 2017-11-02 11:38:37.036 TestApp[6549:670582] 1----<NSThread: 0x61800006f2C0 >{number = 3, name = (null)} 2017-11-02 11:38:37.036 TestApp[6549:670603] 2----<NSThread: 0x60000006AA80 >{Number = 4, name = (null)} 2017-11-02 11:38:37.036 TestApp[6549:670582] 1----<NSThread: 0x61800006f2C0 >{number = 3, name = (null)} 2017-11-02 11:38:37.036 TestApp[6549:670603] 2----<NSThread: 0x60000006AA80 >{Number = 4, name = (null)} 2017-11-02 11:38:37.036 TestApp[6549:670582] 1----<NSThread: 0x61800006f2C0 >{number = 3, name = (null)} 2017-11-02 11:38:37.036 TestApp[6549:670582] barri =====<NSThread: 0x61800006f2C0 >{number = 3, name = (null)} 2017-11-02 11:38:37.036 TestApp[6549:670582] 4----<NSThread: 0x61800006f2C0 >{number = 3, name = (null)} 2017-11-02 11:38:37.036 TestApp[6549:670603] 5----<NSThread: 0x60000006AA80 >{Number = 4, name = (null)} 2017-11-02 11:38:37.036 TestApp[6549:670582] 4----<NSThread: 0x61800006f2C0 >{number = 3, name = (null)} 2017-11-02 11:38:37.036 TestApp[6549:670603] 5----<NSThread: 0x60000006AA80 >{Number = 4, name = (null)} 2017-11-02 11:38:37.037 TestApp[6549:670582] 4----<NSThread: 0x61800006f2C0 >{number = 3, name = (null)} 2017-11-02 11:38:37.037 TestApp[6549:670603] 5----<NSThread: 0x60000006aa80>{number = 4, name = (null)}Copy the code

As a result, although we are creating parallel asynchronous execution, the code below barri will not be executed until the execution above barri completes

To add another important concept,GCD’s semaphore (dispatch_semaphore_t) is also thread-safe, and the program waits when the signal is not zero

dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT); dispatch_semaphore_t sema = dispatch_semaphore_create(1); NSMutableArray *array = [NSMutableArray arrayWithCapacity:1]; for (int i = 0; i < 10; I++) {@autoreleasepool {dispatch_async(queue, ^{// async thread, not blocking others run dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); NSLog(@" semaphore decrement "); // Wait for the signal (semaphore decrement) to continue until it is not 0. [array addObject:[NSNumber numberWithInt:i]]; dispatch_semaphore_signal(sema); // Semaphore plus 1 NSLog(@" signal plus "); }); }}Copy the code