GCD的理解与使用

GCD的理解与使用


在这之前先很通俗理解几个基本的概念:
队列(queue):队列是相对任务而言的,队列是一个存放任务的地方。
任务(task):需要做啥?把需要做的事情“打包”成一个任务,再塞入自己所能“掌握”的队列里面。
调度:对列有了,里面也有任务了。那么任务需要在什么时候被开始?


先了解一下队列的四种优先级

/**
 *  全局队列的四种优先级
 *
 *  DISPATCH_QUEUE_PRIORITY_HIGH
 *  DISPATCH_QUEUE_PRIORITY_DEFAULT
 *  DISPATCH_QUEUE_PRIORITY_LOW
 *  DISPATCH_QUEUE_PRIORITY_BACKGROUND
 *  被设置成后台级别的队列,它会等待所有比它级别高的队列中的任务执行完成或者CPU空闲的时候才会执行自己的任务。
 *  例如磁盘的读写操作非常耗时,如果我们不需要立即获取到磁盘的数据,我们可以把读写任务放到后台队列中,这样读写任务只会在恰当的时候去执行,
 *  从而让程序更加有效率。
 */
#pragma mark - 只执行一次的函数,多用于单例化
- (void)dispatchOnceToken {
    static dispatch_once_t onceToken;
    for (NSInteger i = 0; i < 10; i++) {
        /// 只会在i == 0的时候进入一次,并且推出再进来,NSLog(@"%ld",i);永远不会再走了
        dispatch_once(&onceToken, ^{
            NSLog(@"%ld",i);
        });
    }
}

主要用于单例化。

#pragma mark - 同步和异步
- (void)asycnAction {
    weakSelf(self);
    /// 异步全局队列,并塞入一个任务
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        /// 做一个延迟操作
        sleep(5);
        /// 回到主线程(主线程默认是一个串行队列,所以这边用sync和async的效果是一样的)

        /**
         * 这边如果都使用weakself就不会产生强引用,退出当前VC之后立马dealloc
         * 但是延迟操作之后,该任务还是会被执行,但是此时weakself为nil,所有任务表现为无效
         *
         * 如果其中一个使用self,便会产品强引用
         */
        dispatch_sync(dispatch_get_main_queue(), ^{
            [weakSelf printNum:@"123"];
        });

        dispatch_async(dispatch_get_main_queue(), ^{
            /// 这边使用self会产生强引用,退出当前VC之后并不会立刻dealloc
            [self printNum:@"456"];
        });
    });
}

其实,主线程(main)就是一个串行队列,也是UI的绘制线程,所以保证main线程的通畅是“代码”需要考虑深究的。

#pragma mark - 自定义队列
- (void)customQueue {
    /// 串行队列
    /// PS:dispatch_queue_attr_t设置成NULL的时候默认代表串行。
    dispatch_queue_t serialQueue;
    serialQueue = dispatch_queue_create("com.example.SerialQueue", NULL);

    /// 并发队列
    dispatch_queue_t concurrentQueue;
    concurrentQueue = dispatch_queue_create("com.example.ConcurrentQueue", DISPATCH_QUEUE_CONCURRENT);

}

自定义队列,可以在需要手动管理的时候,通过自定义的队列名称,获取到相关的队列,进行挂起等操作。

#pragma mark - 挂起、恢复队列
- (void)suspendAndResumeQueue {
    dispatch_queue_t globaleQueue = dispatch_get_global_queue(0, 0);

    /// 挂起队列。挂起操作并不会对已经开始执行的任务起作用,仅会阻止队列中还未开始的任务
    dispatch_suspend(globaleQueue);

    /// 恢复队列
    dispatch_resume(globaleQueue);
}

要慎用线程的挂起操作。

#pragma mark - 信号量的使用
/**
 *  信号量的作用是控制多个任务对有限数量资源的访问。
 *  简单来说就是,如果你创建一个有着两个资源的信号量,那么最多同时只能有两个线程可以访问临界区,其它想使用资源的线程必须在FIFO队列里面等待
 */
- (void)dispatchSemaphores {
    weakSelf(self);

    /// 创建一个信号量
    dispatch_semaphore_t t = dispatch_semaphore_create(1);

    dispatch_queue_t concurrentQueue1;
    concurrentQueue1 = dispatch_queue_create("com.example.ConcurrentQueue1", DISPATCH_QUEUE_CONCURRENT);


    dispatch_queue_t concurrentQueue2;
    concurrentQueue2 = dispatch_queue_create("com.example.ConcurrentQueue2", DISPATCH_QUEUE_CONCURRENT);


    dispatch_queue_t concurrentQueue3;
    concurrentQueue3 = dispatch_queue_create("com.example.ConcurrentQueue3", DISPATCH_QUEUE_CONCURRENT);

    /** 需要在每一个队列里面通过dispatch_semaphore_wait这个来等待信号量*/

    dispatch_async(concurrentQueue1, ^{
        /// 避免数据的抢夺
        dispatch_semaphore_wait(t, DISPATCH_TIME_FOREVER);
        for (NSInteger i = 0; i < 10; i++) {
            NSLog(@"第一队列:i=%ld",i);
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            /// 使用完数据,发送一个信号
            [weakSelf printNum:@"第一队列任务结束了"];
            dispatch_semaphore_signal(t);
        });
    });

    dispatch_async(concurrentQueue2, ^{
        dispatch_semaphore_wait(t, DISPATCH_TIME_FOREVER);
        for (NSInteger i = 0; i < 10; i++) {
            NSLog(@"第二队列_____:i=%ld",i);
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            /// 使用完数据,发送一个信号
            [weakSelf printNum:@"第二队列:任务结束了"];
            dispatch_semaphore_signal(t);
        });
    });

    dispatch_async(concurrentQueue3, ^{
        dispatch_semaphore_wait(t, DISPATCH_TIME_FOREVER);
        for (NSInteger i = 0; i < 10; i++) {
            NSLog(@"第三队列——————:i=%ld",i);
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            /// 使用完数据,发送一个信号
            [weakSelf printNum:@"第三队列:任务结束了"];
            dispatch_semaphore_signal(t);
        });
    });
}

下面是打印结果:
2017-07-03 15:17:55.109 Functions[13737:1176065] 第一队列:i=0
2017-07-03 15:17:55.109 Functions[13737:1176065] 第一队列:i=1
2017-07-03 15:17:55.110 Functions[13737:1176065] 第一队列:i=2
2017-07-03 15:17:55.110 Functions[13737:1176065] 第一队列:i=3
2017-07-03 15:17:55.110 Functions[13737:1176065] 第一队列:i=4
2017-07-03 15:17:55.110 Functions[13737:1176065] 第一队列:i=5
2017-07-03 15:17:55.110 Functions[13737:1176065] 第一队列:i=6
2017-07-03 15:17:55.111 Functions[13737:1176065] 第一队列:i=7
2017-07-03 15:17:55.111 Functions[13737:1176065] 第一队列:i=8
2017-07-03 15:17:55.111 Functions[13737:1176065] 第一队列:i=9
2017-07-03 15:17:55.126 Functions[13737:1175989] 第一队列任务结束了
2017-07-03 15:17:55.126 Functions[13737:1176068] 第二队列_____:i=0
2017-07-03 15:17:55.126 Functions[13737:1176068] 第二队列_____:i=1
2017-07-03 15:17:55.126 Functions[13737:1176068] 第二队列_____:i=2
2017-07-03 15:17:55.127 Functions[13737:1176068] 第二队列_____:i=3
2017-07-03 15:17:55.127 Functions[13737:1176068] 第二队列_____:i=4
2017-07-03 15:17:55.127 Functions[13737:1176068] 第二队列_____:i=5
2017-07-03 15:17:55.127 Functions[13737:1176068] 第二队列_____:i=6
2017-07-03 15:17:55.127 Functions[13737:1176068] 第二队列_____:i=7
2017-07-03 15:17:55.127 Functions[13737:1176068] 第二队列_____:i=8
2017-07-03 15:17:55.128 Functions[13737:1176068] 第二队列_____:i=9
2017-07-03 15:17:55.128 Functions[13737:1175989] 第二队列:任务结束了
2017-07-03 15:17:55.128 Functions[13737:1176107] 第三队列——————:i=0
2017-07-03 15:17:55.128 Functions[13737:1176107] 第三队列——————:i=1
2017-07-03 15:17:55.128 Functions[13737:1176107] 第三队列——————:i=2
2017-07-03 15:17:55.128 Functions[13737:1176107] 第三队列——————:i=3
2017-07-03 15:17:55.129 Functions[13737:1176107] 第三队列——————:i=4
2017-07-03 15:17:55.129 Functions[13737:1176107] 第三队列——————:i=5
2017-07-03 15:17:55.129 Functions[13737:1176107] 第三队列——————:i=6
2017-07-03 15:17:55.129 Functions[13737:1176107] 第三队列——————:i=7
2017-07-03 15:17:55.129 Functions[13737:1176107] 第三队列——————:i=8
2017-07-03 15:17:55.129 Functions[13737:1176107] 第三队列——————:i=9
2017-07-03 15:17:55.129 Functions[13737:1175989] 第三队列:任务结束了

可以把每一个i想象成几个线程共享数据的使用,每一次调用都是一次使用,根据打印结果可以看出,不同队列之间,不会在同一时刻同时调用打印i。

其实,可以通过信号量或者干脆点,直接用串行(异步相对于main的串行队列)来避免资源的抢夺。

#pragma mark - Dispatch Groups的使用
/**
 *  是一个可以阻塞线程直到一个或多个任务完成的一种方式
 *  在那些需要等待任务完成才能执行某个处理的时候,可以使用这个方法
 */
- (void)dispatchGroup {
    weakSelf(self);

    dispatch_queue_t concurrentQueue1;
    concurrentQueue1 = dispatch_queue_create("com.example.ConcurrentQueue1", DISPATCH_QUEUE_CONCURRENT);


    dispatch_queue_t concurrentQueue2;
    concurrentQueue2 = dispatch_queue_create("com.example.ConcurrentQueue2", DISPATCH_QUEUE_CONCURRENT);


    dispatch_queue_t concurrentQueue3;
    concurrentQueue3 = dispatch_queue_create("com.example.ConcurrentQueue3", DISPATCH_QUEUE_CONCURRENT);

    dispatch_group_t groupQueue = dispatch_group_create();

    dispatch_group_async(groupQueue, concurrentQueue1, ^{
        for (NSInteger i = 0; i < 1000; i++) {
            NSLog(@"第一队列:i=%ld",i);
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            /// 使用完数据,发送一个信号
            [weakSelf printNum:@"第一队列任务结束了"];
        });
    });

    dispatch_group_async(groupQueue, concurrentQueue2, ^{
        for (NSInteger i = 0; i < 1000; i++) {
            NSLog(@"第二队列_____:i=%ld",i);
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            /// 使用完数据,发送一个信号
            [weakSelf printNum:@"第二队列:任务结束了"];
        });
    });

    dispatch_group_async(groupQueue, concurrentQueue3, ^{
        for (NSInteger i = 0; i < 1000; i++) {
            NSLog(@"第三队列——————:i=%ld",i);
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            /// 使用完数据,发送一个信号
            [weakSelf printNum:@"第三队列:任务结束了"];
        });
    });

    dispatch_group_async(groupQueue, dispatch_get_global_queue(0, 0), ^{
//        dispatch_async(dispatch_get_global_queue(0, 0), ^{
//            for (NSInteger i = 0; i < 100000; i++) {
//                NSLog(@"全局队列——————:i=%ld",i);
//            }
//        });

        /// 这种情况下,dispatch_group_notify会一直等待它完成,但是如果是上面那种情况,内部再开一个异步并行的,dispatch_group_notify就不会等待,或者说捕捉不到该等待,所以对于网络请求(基本都是异步请求的),是不可以同时放几个请求在group下面,用来等待全部完成的时候refreshUI的
        for (NSInteger i = 0; i < 100000; i++) {
            NSLog(@"全局队列——————:i=%ld",i);
        }
    });

    dispatch_group_notify(groupQueue, dispatch_get_main_queue(), ^{
        NSLog(@"三个任务都完成了");
    });
}

对于多个任务,可以开启多个异步并行队列,同时开启多个任务(如果CPU支持的话),用dispatch_group_notify来等待最终的结果。但是不可以在单个队列内部再开启一个异步并行队列(比如UI的刷新同时依赖几个请求的完成),dispatch_group_async是无法捕捉到这样的结束的。

以上就是我对GCD的基本了解以及GCD的常用API,如有错误,希望不吝指正,谢谢!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值