I recently read about GCD again. I just kept on using the function in a simple way. Now I have a little more understanding and a summary.
In fact, when using the GCD function, it is easy to notice that a word often appears, that is, dispatch. I checked the meaning of dispatch and dispatch. My current understanding of GCD is based on this word. Although it is a multi-threaded programming method, we do not need to directly manage and manipulate threads, but assign tasks (methods, code blocks, and other forms) to specific queues ), then these queues will dispatch these tasks to various threads, as if there are several very powerful clerks, as long as they send the tasks to them, they will assign the task to the correct thread. I think the core thing is that these queues distribute and dispatch tasks, which means dispatch. Compared with the direct management thread, GCD has some more queue, and these queue are assigned tasks, so I think these queues and their assignment of tasks are the key to gcd (now I understand this level ......).
Therefore, there are two parts to understand: 1. What queues are available and their properties 2. Various functions can be used to perform different operations in the same queue, in fact, this is a step that affects the queue distribution (dispatch. To sum up, it is the question of what queue to choose and what operations to perform.
1. queue:
The queue type is dispatch_queue_t. It can be divided into two types: built-in and custom. The system comes with four queues. The first is the main queue column.
Dispatch_get_main_queue ()
And then 3 Global queue.
Dispatch_get_global_queue (dispatch_queue_priority_default, 0)
The first of the two parameters is the priority. The three queues have three priorities: High, Medium, and low. If default is used, it is medium. The second parameter is unknown for the moment.
The custom queue is constructed through:
Dispatch_queue_t queue = dispatch_queue_create ("first", dispatch_queue_serial );
The first parameter indicates the queue using a string, and the second parameter indicates whether the queue is serial or parallel. In a serial queue, a task is returned only after it is executed. Even if dispatch_async is used, asynchronous methods such as dispatch_async will return immediately, and the program will continue to run downward without blocking. Other functions such as dispatch_sync can also achieve effects similar to serial queues, that is to say, this code block must be executed before it can continue to be executed.
2. functions:
Almost all functions in GCD are in the form of function pointers and blocks. The difference above is that a _ f extension is used for function pointers, in fact, we can see that the function pointer and block are similar in function.
(1) first, the most common is: for example, dispatch_async, Implement Asynchronous call. The code above is:
- (void)disptch_sync_test{ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ sleep(2); //线程沉睡2秒模拟该操作执行了一段时间 NSLog(@"串行"); }); dispatch_async(queue, ^{ sleep(2); NSLog(@"并行"); }); NSLog(@"结束");}
The execution result is:
2014-10-12 14:32:12.047 GCD_Demo[763:41657] 结束2014-10-12 14:32:14.048 GCD_Demo[763:41689] 并行2014-10-12 14:32:14.048 GCD_Demo[763:41687] 串行
The output of "end" is at the beginning, indicating that the code in the first two blocks has not been executed and runs to nslog (@ "end.
Similar to dispatch_sync, it will block the thread and the program will continue to run down after it is executed. For example, change the first function in the above example:
- (void)disptch_sync_test{ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_sync(queue, ^{ //改了这里,少了个a sleep(2); NSLog(@"串行"); }); dispatch_async(queue, ^{ sleep(2); NSLog(@"并行"); }); NSLog(@"结束");}
The running result is changed:
2014-10-12 14:37:14.928 GCD_Demo[825:44430] 串行2014-10-12 14:37:14.929 GCD_Demo[825:44430] 结束2014-10-12 14:37:16.930 GCD_Demo[825:44466] 并行
The output of "serial" is at the beginning, indicating that the code of the first block must be returned after execution, so that it will continue to be called asynchronously because the second function has not been modified, therefore, the output of "end" is in front of "Parallel.
(2) Sometimes this is the case. For example, the construction of a Class Object S requires two different parameters, for example, A and B. Each of them requires an operation to obtain them, however, A and B are not correlated with each other, so we will certainly use Asynchronous concurrency to obtain A and B respectively, so we can get a and B at the same time. The code may be written as follows:
- (void)disptch_sync_test{ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ sleep(2); NSLog(@"获取A"); //这里代表执行操作获取A //(11) }); dispatch_async(queue, ^{ sleep(4); NSLog(@"获取B"); //这里代表操作获取B //(22) }); NSLog(@"使用A和B构建S"); //这里代表操作构建S}
However, when building S, A and B are still being executed, so no. So what should we do if we put the building s at the (11) position and followed it to get a for execution, but B won't get it, and put it at the (22) location? For example:
- (void)disptch_sync_test{ dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); __block BOOL finish_A = NO,finish_B = NO; //使用__block修饰,以便在block内部修改值 dispatch_async(queue, ^{ sleep(2); NSLog(@"获取A"); //这里代表执行操作获取A finish_A = YES; if (finish_A && finish_B) { [self constructS]; } //(11) }); dispatch_async(queue, ^{ sleep(4); NSLog(@"获取B"); //这里代表操作获取B finish_B = YES; if (finish_A && finish_B) { [self constructS]; } //(22) }); //NSLog(@"使用A和B构建S"); //这里代表操作构建S}-(void )constructS{ NSLog(@"使用A和B构建S"); //这里代表操作构建S}
However, this kind of console is troublesome and requires additional variables and methods to be defined. If you use dispatch group, it can be well solved. Example:
- (void)disptch_sync_test{ 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, ^{ sleep(2); NSLog(@"获取A"); //这里代表执行操作获取A }); dispatch_group_async(group, queue, ^{ sleep(4); NSLog(@"获取B"); //这里代表操作获取B }); dispatch_group_notify(group, queue, ^{ NSLog(@"使用A和B构建S"); //这里代表操作构建S });}
In my understanding, a group is used to bind multiple operations to a certain extent, and then the tasks called using dispatch_group_async are executed asynchronously without waiting for the execution to complete, in this way, A and B are obtained at the same time, but the code executed using dispatch_group_notify will not be executed until dispatch_group_async is executed. Therefore, the above requirements can be well solved, which is relatively simple and clear at a glance.
(3)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), queue, ^{ NSLog(@"XXX"); });
You can specify the time after which the task will be executed, which is more concise than nstimer, if you do not want to perform repetitive operations. It seems that the time precision is better than nstimer, because we have seen that the source code for parsing Video Frames uses this method to determine the time of the next frame. The specific precision is unclear.
(4)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply(10, queue, ^(size_t idx) { sleep(2); NSLog(@"XXXX %zu",idx); //传入的参数是调用的次数序号 });
It can be used to execute the statement block in the block multiple times. From the output, we can see that recursion should be adopted, but the specific method of recursion is not quite understandable.
(5)
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"XXXX"); });
It ensures that the code in the block is executed only once in the life cycle of the program, so it is often used to build a singleton.
A Brief Introduction to GCD