Sharing is an essential quality for every good programmer
Introduction to the
GCD
- Grand Central Dispatch: Great Central scheduler
- Pure C language, provides a lot of powerful functions
advantage
- GCD is apple’s solution to multi-core parallel computing
- – GCDS automatically utilize more CPU cores (such as dual core, quad core)
- GCD automatically manages thread lifecycles (thread creation, task scheduling, thread destruction)
- The programmer only needs to tell the COMMUNIST party what task it wants to perform, without writing any thread management code
The core concept
- Task: What operation is performed
- Queue: Used to store tasks
The queue
Create the queue using the dispatch_queue_create function
// Parameter 2: queue type DISPATCH_QUEUE_CONCURRENT: concurrent,SERIAL: Serial dispatch_queue_t queue = dispatch_queue CREATE (NULL, DISPATCH_QUEUE_SERIAL);Copy the code
Queues have four priorities
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // high #define DISPATCH_QUEUE_PRIORITY_DEFAULT DISPATCH_QUEUE_PRIORITY_LOW (-2) // low #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MINCopy the code
Note: Global queues exist by default throughout the application, and there are four concurrent queues: high, default, low, and background priority. Using create creates a new queue manually.
Concurrent Dispatch Queue
- Enables concurrent execution of multiple tasks (automatically enabling multiple threads to execute tasks simultaneously)
- Concurrency is only available with asynchronous (dispatch_async) functions
The GCD provides a global concurrent queue by default for the entire application. You do not need to manually create a global concurrent queue using the dispatch_get_global_queue function
// Parameter 1: queue priority dispatch_queue_priority_t Dispatch_queue_t queue = dispatch_get_global_queue(0, 0);Copy the code
Serial Dispatch Queue
- Allow tasks to be executed one after another (after one task is completed, proceed to the next)
There are two ways to get serial in GCD
1. Create a serial queue using dispatch_queue_CREATE
Dispatch_queue_t queue = dispatch_queue_CREATE ("RC", NULL);Copy the code
2, use the main queue (queue associated with the main thread)
- The main queue is a special serial queue that comes with the GCD
- Tasks placed in the main queue are executed in the main thread
Get the primary queue using dispatch_get_main_queue()
dispatch_queue_t queue = dispatch_get_main_queue()
Copy the code
The use of the GCD
- 1. Customize tasks and decide what you want to do
- 2. After adding a task to the queue, GCD will automatically take out the task in the queue and put it into the corresponding thread for execution. The task taking out follows the FIFO principle of queue: first in, first out, last in, last out
1. Asynchronous function + concurrent queue: enable multiple threads to execute tasks concurrently
- (void)asyncConcurrent{ // 1. Dispatch_queue_t queue = dispatch_get_global_queue(0, 0); NSLog(@"---satrt----"); // add dispatch_async(queue, ^{NSLog(@"1----%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"2----%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"3----%@",[NSThread currentThread]); }); NSLog(@"---end----"); }Copy the code
Print:
RCGCDDemo[3650:175994] ---satrt----
RCGCDDemo[3650:175994] ---end----
RCGCDDemo[3650:176035] 2----<NSThread: 0x600002895d40>{number = 3, name = (null)}
RCGCDDemo[3650:176114] 1----<NSThread: 0x600002895c80>{number = 4, name = (null)}
RCGCDDemo[3650:176115] 3----<NSThread: 0x60000289ae80>{number = 5, name = (null)}
Copy the code
Note: there is not a single thread for each task. The system decides how many threads to start
2, asynchronous function + serial queue: start a thread, serial execution of the task
- (void)asyncSerial{//1. Create queue dispatch_queue_t queue = dispatch_queue_create("RC", DISPATCH_QUEUE_SERIAL); NSLog(@"---satrt----"); dispatch_async(queue, ^{ NSLog(@"1----%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"2----%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"3----%@",[NSThread currentThread]); }); NSLog(@"---end----"); }Copy the code
Print:
RCGCDDemo[3765:181439] ---satrt----
RCGCDDemo[3765:181439] ---end----
RCGCDDemo[3765:181473] 1----<NSThread: 0x600001013740>{number = 3, name = (null)}
RCGCDDemo[3765:181473] 2----<NSThread: 0x600001013740>{number = 3, name = (null)}
RCGCDDemo[3765:181473] 3----<NSThread: 0x600001013740>{number = 3, name = (null)}
Copy the code
3, synchronization function + concurrent queue: no thread, serial execution of the task
-(void)syncConcurrent{
dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
NSLog(@"---start---");
dispatch_sync(queue, ^{
NSLog(@"1----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3----%@",[NSThread currentThread]);
});
NSLog(@"---end----");
}
Copy the code
Print:
RCGCDDemo[3825:184734] ---start---
RCGCDDemo[3825:184734] 1----<NSThread: 0x600000c19400>{number = 1, name = main}
RCGCDDemo[3825:184734] 2----<NSThread: 0x600000c19400>{number = 1, name = main}
RCGCDDemo[3825:184734] 3----<NSThread: 0x600000c19400>{number = 1, name = main}
RCGCDDemo[3825:184734] ---end----
Copy the code
4, synchronization function + serial queue: no thread, serial execution of the task
-(void)syncSerial{
dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
NSLog(@"---start---");
dispatch_sync(queue, ^{
NSLog(@"1----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3----%@",[NSThread currentThread]);
});
NSLog(@"---end----");
}
Copy the code
Print:
RCGCDDemo[3909:189316] ---start---
RCGCDDemo[3909:189316] 1----<NSThread: 0x600003644fc0>{number = 1, name = main}
RCGCDDemo[3909:189316] 2----<NSThread: 0x600003644fc0>{number = 1, name = main}
RCGCDDemo[3909:189316] 3----<NSThread: 0x600003644fc0>{number = 1, name = main}
RCGCDDemo[3909:189316] ---end----
Copy the code
5, asynchronous function + main queue: do not open the thread, in the main thread serial execution of the task
-(void)asyncMain{dispatch_queue_t queue = dispatch_get_main_queue(); NSLog(@"---start---"); dispatch_async(queue, ^{ NSLog(@"1----%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"2----%@",[NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"3----%@",[NSThread currentThread]); }); NSLog(@"---end----"); }Copy the code
Print:
RCGCDDemo[4050:195922] ---start---
RCGCDDemo[4050:195922] ---end----
RCGCDDemo[4050:195922] 1----<NSThread: 0x6000013ead80>{number = 1, name = main}
RCGCDDemo[4050:195922] 2----<NSThread: 0x6000013ead80>{number = 1, name = main}
RCGCDDemo[4050:195922] 3----<NSThread: 0x6000013ead80>{number = 1, name = main}
Copy the code
6, synchronization function + main queue: do not open the thread, sequential execution of the task (note that deadlock occurs)
Note: this method is executed in the main thread with a deadlock; This method is executed in the child thread, so all tasks are executed in the main thread.
-(void)syncMain{
dispatch_queue_t queue = dispatch_get_main_queue();
NSLog(@"start----");
dispatch_sync(queue, ^{
NSLog(@"1----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"2----%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3----%@",[NSThread currentThread]);
});
NSLog(@"end---");
}
Copy the code
Execution of the -(void)syncMain method on the main thread causes a deadlock due to waiting for each other and crashes the program! If this method is executed on the main thread, tasks 1, 2, and 3 will also be executed on the main thread because they are added to the main queue. The main thread is waiting for tasks 1, 2, and 3 to complete before executing other tasks. The main thread is waiting for tasks 1, 2, and 3 to complete before executing other tasks. -(void)syncMain -(void)syncMain -(void)syncMain -(void)syncMain
Print performed in a child thread:
RCGCDDemo[4104:198438] start----
RCGCDDemo[4104:198392] 1----<NSThread: 0x600001f2c700>{number = 1, name = main}
RCGCDDemo[4104:198392] 2----<NSThread: 0x600001f2c700>{number = 1, name = main}
RCGCDDemo[4104:198392] 3----<NSThread: 0x600001f2c700>{number = 1, name = main}
RCGCDDemo[4104:198438] end---
Copy the code
Communication between GCD threads
Take downloading in child threads and displaying the main thread as an example
- (void)laodImg{dispatch_async(dispatch_get_global_queue(0, 0), ^{dispatch_get_main_queue(), ^{// display image}); }); }Copy the code
GCD common functions
Delay function
//[selformSelector :@selector(task) withObject:nil afterDelay:1.0]; / / 2. Delay the second method / / [NSTimer scheduledTimerWithTimeInterval: 1.0 target: self selector: @ the selector (task) the userInfo: nil repeats:YES]; GCD /* Parameter 1: DISPATCH_TIME_NOW Count time from now * parameter 2: delay time 1.0 GCD time unit: nanoseconds * parameter 3: DISPATCH_TIME_NOW */ dispatch_queue_t queue = dispatch_get_global_queue(0, 0); Dispatch_after (dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), queue, ^{//}); }Copy the code
Fence function (controlling the order in which tasks are executed)
There are two functions: dispatch_barrier_async and dispatch_barrier_sync
Note: when using the barrier function, it makes sense to use a custom queue. If you are using a serial queue or a system-provided global concurrent queue, the barrier function functions as a synchronization function
dispatch_barrier_async
Code:
- (void)barrierAsync{
dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
NSLog(@"---satrt----");
dispatch_async(queue, ^{
NSLog(@"1----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2----%@",[NSThread currentThread]);
});
dispatch_barrier_async(queue, ^{
NSLog(@"3----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"4----%@",[NSThread currentThread]);
});
NSLog(@"---end----");
}
Copy the code
Print:
RCGCDDemo[4559:227700] ---satrt----
RCGCDDemo[4559:227700] ---end----
RCGCDDemo[4559:230128] 2----<NSThread: 0x600002f5f0c0>{number = 8, name = (null)}
RCGCDDemo[4559:228512] 1----<NSThread: 0x600002f5e840>{number = 5, name = (null)}
RCGCDDemo[4559:228512] 3----<NSThread: 0x600002f5e840>{number = 5, name = (null)}
RCGCDDemo[4559:228512] 4----<NSThread: 0x600002f5e840>{number = 5, name = (null)}
Copy the code
Available:
- Tasks that precede a Barrier are executed concurrently
- Once the barrier is executed, subsequent tasks can be inserted into the queue without completing the barrier, but they still need to be completed before they can be executed.
dispatch_barrier_sync
- (void)barrierSync{
dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
NSLog(@"---satrt----");
dispatch_async(queue, ^{
NSLog(@"1----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2----%@",[NSThread currentThread]);
});
dispatch_barrier_sync(queue, ^{
NSLog(@"3----%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"4----%@",[NSThread currentThread]);
});
NSLog(@"---end----");
}
Copy the code
Print:
RCGCDDemo[4653:234416] ---satrt----
RCGCDDemo[4653:234775] 1----<NSThread: 0x600001783580>{number = 5, name = (null)}
RCGCDDemo[4653:235167] 2----<NSThread: 0x60000178e6c0>{number = 8, name = (null)}
RCGCDDemo[4653:234416] 3----<NSThread: 0x6000017d1400>{number = 1, name = main}
RCGCDDemo[4653:234416] ---end----
RCGCDDemo[4653:235167] 4----<NSThread: 0x60000178e6c0>{number = 8, name = (null)}
Copy the code
Available:
- Similarly, tasks that precede a Barrier are executed concurrently
- When running to the barrier, subsequent tasks must wait until the barrier finishes before they are inserted into the queue to continue execution.
One-time code
Note: can not be lazy loading, mainly used for singleton classes: iOS singleton class details
Rapid iteration
Open multiple threads to complete the iterative operation concurrently
- (void)applyTest{// Enable the child thread to complete the traversal task with the main thread. Parameter 1: number of traversals parameter 2: queue (concurrent queue) parameter 3: Index index */ dispatch_apply(5, dispatch_get_global_queue(0, 0), ^(size_t index) { i<100000; i++){ } NSLog(@"%zd---%@",index,[NSThread currentThread]); }); }Copy the code
Print:
RCGCDDemo[4969:248588] 0---<NSThread: 0x600002fd5140>{number = 1, name = main}
RCGCDDemo[4969:248654] 2---<NSThread: 0x600002f872c0>{number = 3, name = (null)}
RCGCDDemo[4969:248652] 1---<NSThread: 0x600002f87080>{number = 4, name = (null)}
RCGCDDemo[4969:248655] 3---<NSThread: 0x600002f87280>{number = 5, name = (null)}
RCGCDDemo[4969:248588] 4---<NSThread: 0x600002fd5140>{number = 1, name = main}
Copy the code
Queue group
Dispatch_group_t group = dispatch_group_create(); Dispatch_group_notify Intercepts notification of completion of all tasks in the queue group:
- (void)groupTest{// 1. Create a queue dispatch_queue_t queue = dispatch_get_global_queue(0, 0); // 2. Create queue group dispatch_group_t group = dispatch_group_create(); NSLog(@"---satrt----"); // 3. Add a task, monitor the execution of the task, notify group dispatch_group_async(group, queue, ^{NSLog(@"1----%@",[NSThread currentThread]); }); dispatch_group_async(group, queue, ^{ NSLog(@"2----%@",[NSThread currentThread]); }); dispatch_group_async(group, queue, ^{ NSLog(@"3----%@",[NSThread currentThread]); }); NSLog(@"-------come,baby"); // Intercepts notifications, dispatch_group_notify(group, queue, ^{NSLog(@"-------come,baby"); }); NSLog(@"---end----"); }Copy the code
Print:
RCGCDDemo[934:25071] ---satrt----
RCGCDDemo[934:25071] ---end----
RCGCDDemo[934:25126] 1----<NSThread: 0x600003ec8640>{number = 5, name = (null)}
RCGCDDemo[934:25125] 3----<NSThread: 0x600003ecc800>{number = 4, name = (null)}
RCGCDDemo[934:25124] 2----<NSThread: 0x600003ec8740>{number = 6, name = (null)}
RCGCDDemo[934:25124] -------come,baby
Copy the code
The dispatch_group_notify function is executed asynchronously and does not block the thread.
You can also use dispatch_group_enter and dispatch_group_leave for the same purpose. Dispatch_group_enter enables subsequent asynchronous tasks to be monitored by the queue group. The two methods must be paired using code:
- (void)groupTest2{ dispatch_queue_t queue = dispatch_get_global_queue(0, 0); dispatch_group_t group = dispatch_group_create(); NSLog(@"---satrt----"); Dispatch_group_enter (group); dispatch_async(queue, ^{ NSLog(@"1----%@",[NSThread currentThread]); // Dispatch_group_leave (group); }); dispatch_group_enter(group); dispatch_async(queue, ^{ NSLog(@"2----%@",[NSThread currentThread]); dispatch_group_leave(group); }); dispatch_group_enter(group); dispatch_async(queue, ^{ NSLog(@"3----%@",[NSThread currentThread]); dispatch_group_leave(group); }); NSLog(@"-------come,baby"); // Intercepts notifications, dispatch_group_notify(group, queue, ^{NSLog(@"-------come,baby"); }); NSLog(@"---end----"); }Copy the code
Print:
RCGCDDemo[993:28534] ---satrt----
RCGCDDemo[993:28534] ---end----
RCGCDDemo[993:28621] 1----<NSThread: 0x6000002af600>{number = 3, name = (null)}
RCGCDDemo[993:28868] 3----<NSThread: 0x6000002afbc0>{number = 5, name = (null)}
RCGCDDemo[993:28867] 2----<NSThread: 0x6000002a2340>{number = 4, name = (null)}
RCGCDDemo[993:28867] -------come,baby
Copy the code
You can also use dispatch_group_wait to listen for tasks in a queue group, which itself blocks until all tasks in the queue group have finished executing.
// Block dispatch_group_wait(group, DISPATCH_TIME_FOREVER) until all tasks in the queue group have been executed; NSLog(@"---end----");Copy the code
Print:
RCGCDDemo[1054:32183] ---satrt----
RCGCDDemo[1054:32242] 1----<NSThread: 0x600000f5f480>{number = 3, name = (null)}
RCGCDDemo[1054:32241] 3----<NSThread: 0x600000f5f780>{number = 6, name = (null)}
RCGCDDemo[1054:32240] 2----<NSThread: 0x600000f5f300>{number = 4, name = (null)}
RCGCDDemo[1054:32183] ---end----
Copy the code
End is printed only after tasks 1, 2, and 3 are completed.