GCD 并行队列使用

通常情况下,我们在处理网络请求和处理大数据时,会使用多线程技术,在新线程中进行操作,防止主线程卡顿,降低用户体验.

1.基本操作
步骤:新建线程,处理数据,返回主线程刷新UI

//0.开启新线程
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
//1.此处处理数据
//doSomething

//2.返回主线程
dispatch_sync(dispatch_get_main_queue(), ^{
//3.刷新UI

});

});

2.某个操作依赖其他操作,需要等待其他几个操作完成再去执行。
A.使用GCD的group
步骤:新建队列和group,添加多个操作,注册group完成通知。

//“全部完成”操作 依赖 “1”,“2”,“3”三个操作
    NSLog(@"主线程");
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, globalQueue, ^{
        [NSThread sleepForTimeInterval:1];
        NSLog(@"----- 1 -----");
    });
    dispatch_group_async(group, globalQueue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"----- 2 -----");
    });
    dispatch_group_async(group, globalQueue, ^{
        [NSThread sleepForTimeInterval:3];
        NSLog(@"----- 3 -----");
    });
    dispatch_group_notify(group, globalQueue, ^{
        NSLog(@"全部完成");
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"主线程");
        });
    });
1.png

从控制台信息可以看到。“全部完成”是在三个线程执行完成后调用的。从线程ID看到,打印“全部完成”的线程是三个线程中最后结束的那个线程。

B.使用栅栏隔离
步骤:新建并行队列,添加优先执行的操作,添加栅栏,添加后执行的操作

    dispatch_queue_t current1 = dispatch_queue_create("myQueue1", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(current1, ^{
        for (NSInteger i = 0 ; i < 2; i++) {
            NSLog(@"1");
        }
    });
    dispatch_async(current1, ^{
        for (NSInteger i = 0 ; i < 2; i++) {
            NSLog(@"2");
        }
    });
    dispatch_barrier_async(current1, ^{
        NSLog(@"隔离作用");
    });
    dispatch_async(current1, ^{
        for (NSInteger i = 0 ; i < 2; i++) {
            NSLog(@"3");
        }
    });
    dispatch_async(current1, ^{
        for (NSInteger i = 0 ; i < 2; i++) {
            NSLog(@"4");
        }
    });
2.png

执行完1.2两个操作,然后才执行3.4操作。并且从线程ID看,“隔离操作”使用了“2”的线程,“隔离操作”完成后,“3”又使用了这个线程,系统并未给“3”“4”新建线程,而是使用了旧线程,节约了系统开销。

要知道实际此处有apple提供了两个方法,dispatch_barrier_async 和 dispatch_barrier_sync,两者区别在哪呢?
下面从代码上探究一下
a.在上述代码基础上增加两行log

    NSLog(@"主线程");
    dispatch_queue_t current1 = dispatch_queue_create("myQueue1", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(current1, ^{
        for (NSInteger i = 0 ; i < 2; i++) {
            NSLog(@"1");
        }
    });
    dispatch_async(current1, ^{
        for (NSInteger i = 0 ; i < 2; i++) {
            NSLog(@"2");
        }
    });
    dispatch_barrier_async(current1, ^{
        NSLog(@"隔离作用");
    });
    NSLog(@"aa");
    dispatch_async(current1, ^{
        for (NSInteger i = 0 ; i < 2; i++) {
            NSLog(@"3");
        }
    });
    NSLog(@"bb");
    dispatch_async(current1, ^{
        for (NSInteger i = 0 ; i < 2; i++) {
            NSLog(@"4");
        }
    });

运行结果:

3.png

“aa”和“bb”在隔离前输出。

B.将dispatch_barrier_async 改为 dispatch_barrier_sync
运行结果:

4.png

“aa”和“bb”在隔离后输出。

两者对比发现,控制台输出“aa”,"bb"时间是不同的,一个在隔离前,一个在隔离后,说明在将任务插入到queue的时候,dispatch_barrier_sync需要等待自己的任务(“隔离作用”)结束之后才会插入被写在它后面的任务(3、4);而dispatch_barrier_async将自己的任务(“隔离作用”)插入到queue之后,不会等待自己的任务结束,它会继续把后面的任务(3、4)插入到queue

所以,dispatch_barrier_async的不等待(异步)特性体现在将任务插入队列的过程,它的等待特性体现在任务真正执行的过程。

你可能感兴趣的:(GCD 并行队列使用)