iOS Begins GCD Research (I)

Keywords: Programming network

17 March 2017

GCD (Grand Central Dispatch) is a technology developed by Apple to optimize concurrent operations in multi-core environments and replace traditional multi-threaded programming patterns.

Learn from the simplest.

Serial-Parallel

dispatch_queue in GCD can be roughly divided into three categories

  1. Global parallel queue
  2. Serial queue of main thread
  3. Customized queue

The dispatch_async function runs the incoming block into the specified queue. This function is asynchronous, which means that it will return immediately regardless of whether the block ends or not. Therefore, we can run various time-consuming operations (such as network requests) in a block without blocking UI threads.

dispatch_get_global_queue will get a global queue, which we can understand as some global threads opened for us by the system. We use priority to specify the priority of the queue, while flag is used as a reserve field (usually 0).

#define DISPATCH_QUEUE_PRIORITY_HIGH 2

#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0

#define DISPATCH_QUEUE_PRIORITY_LOW (-2)

#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN

dispatch_get_global_queue has two parameters. The first parameter means the priority with convenience, which is generally the four values above, but not fixed. The second parameter is that the reserved parameter is temporarily useless.

dispatch_get_main_queue returns to the main queue, which is the UI queue. It is generally used when you need to update the interface in the UI queue (such as [self update UI WithResult: result] in the code above) after you have done some work asynchronously in other queues.

These three are relatively basic functions, the following code, combined to see

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    NSLog(@"start task 1");
    [NSThread sleepForTimeInterval:3];//Delay 3 seconds
    NSLog(@"end task 1");
});   
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    NSLog(@"start task 2");
    [NSThread sleepForTimeInterval:3];
    NSLog(@"end task 2");
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    NSLog(@"start task 3");
    [NSThread sleepForTimeInterval:3];
    NSLog(@"end task 3");
});

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    NSLog(@"start task 1");
    [NSThread sleepForTimeInterval:3];
    NSLog(@"end task 1");
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    NSLog(@"start task 2");
    [NSThread sleepForTimeInterval:3];
    NSLog(@"end task 2");
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"start task 3");
    [NSThread sleepForTimeInterval:3];
    NSLog(@"end task 3");
});

So, you can modify the first parameter to control which thread to execute first, but the thread is executed concurrently, so you can't guarantee which thread will execute first, that is, we can't guarantee that the time-consuming tasks are executed in sequence.

So if you want to solve this problem, you use custom queues.

This method is used to create custom queues:
dispatch_queue_create(const char *label, dispatch_queue_attr_t attr).
There are also two parameters. The first parameter is an identifier to determine the unique queue. The second parameter creates the type of queue. Serial or parallel.

/**
 *  We created a serial queue
 *
 *  @param "com.gcd.test.queue"  Uniquely identifies this queue
 *  @param DISPATCH_QUEUE_SERIAL The instructions are serial queue
 */
dispatch_queue_t myQueue = dispatch_queue_create("com.gcd.test.queue", DISPATCH_QUEUE_SERIAL);

dispatch_async(myQueue, ^{
    NSLog(@"start task 1");
    [NSThread sleepForTimeInterval:3];
    NSLog(@"end task 1");
});

dispatch_async(myQueue, ^{
    NSLog(@"start task 2");
    [NSThread sleepForTimeInterval:3];
    NSLog(@"end task 2");
});

dispatch_async(myQueue, ^{
    NSLog(@"start task 3");
    [NSThread sleepForTimeInterval:3];
    NSLog(@"end task 3");
});

You can see from the picture above that 42565 is the ID of the main thread and 1589679 is the ID of the asynchronous thread. We don't all say serial queue, so it's equivalent to the same asynchronous thread. At first, it's concurrent queue, so the ID of asynchronous thread is different.

dispatch_group_queue

In our usual practical projects, we often have the requirement that we need a unified callback notification to handle the next business after asynchronous processing of multiple tasks. At this time, we think of dispatch group. When all tasks are completed, dispatch_group_notify will be called.

/**
 *  Create a concurrent queue
 */
dispatch_queue_t queue = dispatch_queue_create("com.test.gcd.queue", DISPATCH_QUEUE_CONCURRENT);
/**
 *  Create a group
 */
dispatch_group_t group = dispatch_group_create();
/**
 *  Perform three time-consuming tasks
 */
dispatch_group_async(group, queue, ^{
    NSLog(@"start task 1");
    [NSThread sleepForTimeInterval:3];
    NSLog(@"end task 1");
});

dispatch_group_async(group, queue, ^{
    NSLog(@"start task 2");
    [NSThread sleepForTimeInterval:3];
    NSLog(@"end task 2");
});

dispatch_group_async(group, queue, ^{
    NSLog(@"start task 3");
    [NSThread sleepForTimeInterval:3];
    NSLog(@"end task 3");
});
dispatch_group_notify(group, queue, ^{
    NSLog(@"task over");
});

When three asynchronous time-consuming operations are completed, unify a callback. Two points should be noted:

  1. In the data asynchronous thread that calls back, this can be found by the thread ID number 1631915 in front of it. So if subsequent UI refresh operations need to be done in the main thread.

  2. The thread that receives the callback is the thread that the task finally executes. The system has been optimized without opening another thread to process.

Today's study record, that's all. It's late. Good night.

Posted by mpiaser on Sun, 21 Apr 2019 18:24:33 -0700