Objective-C GCD

GCD

GCD全称Grand Central Dispatch; 是由C语言编写而成。

优点

  • GCD 是系统级别运行, 根据应用所需来分配系统资源, 弄够有效的利用多核,是系统或应用所以更快,更高效的运行。
  • 在ARC下 GCD和正常的Object一样,生命周期由系统进行管理。
  • 使用简单按照业务需求,给GCD添加任务即可。

缺点

  • 但是创建过多的线程,会耗费更多的系统资源(主线程1M, 其他线程512KB), 降低系统的性能
  • 线程越多会增加调度的开销

 最直观的表现是 手机发热,耗电快; 所以: 线程虽好,可不要多创建。 

基本使用

同步/异步任务

任务:  就是执行什么操作(做什么)
同步任务: 不会开启新线程, 所以在一个队列中任务按顺序一个一个执行。
异步任务:会根据需要开启新线程, 队列中的任务可以在多个线程执行,相当于同时执行。

串行/并发队列

队列: 存放任务的线性表 先进先出(FIFO)
串行队列: 在此队列上的任务只能使用一个线程。
并行队列:在此队列上的任务根据需要可以使用多个线程。

具体执行顺序是和任务+队列

 任务和队列的组合

系统中包含的队列

主队列

dispatch_get_main_queue();

主队列是串行队列

放入主队列的任务都是是主线程中执行,主线程也称作UI线程,主要做一些用户操作,比如刷新UI, 用户操作事件(点击,滑动等);    因为是串行队列不能向主队列中放入耗时操作,这些会手机卡顿。

全局队列

dispatch_queue_global_t dispatch_get_global_queue(long identifier, unsigned long flags);

全局队列是异步队列 

参数 identifier

iOS8之后 服务质量 QOS(quality of service)
QOS_CLASS_USER_INTERACTIVE UI和动画
QOS_CLASS_USER_INITIATED 用户操作点击 拖拽等
QOS_CLASS_DEFAULT              默认
QOS_CLASS_UTILITY                 耗时操作 如下载等
QOS_CLASS_BACKGROUND   后台操作

与之对应的

DISPATCH_QUEUE_PRIORITY_HIGH:         QOS_CLASS_USER_INITIATED
DISPATCH_QUEUE_PRIORITY_DEFAULT:      QOS_CLASS_DEFAULT
DISPATCH_QUEUE_PRIORITY_LOW:          QOS_CLASS_UTILITY
DISPATCH_QUEUE_PRIORITY_BACKGROUND:   QOS_CLASS_BACKGROUND    

参数 flags

预留参数 传0以外的数可能return NULL

自定义队列

dispatch_queue_t
dispatch_queue_create(const char *_Nullable label,
		dispatch_queue_attr_t _Nullable attr);

const char *_Nullable label

队列标签 队列名 可以在调用栈中看到任务所执行的队列

dispatch_queue_attr_t _Nullable attr

dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0);

第一个参数 : 表示队列的类型 串行/并发

第二个参数: 服务质量

对三个 : 相对优先级 范围[-15, 0]  不在范围内返回NULL

使用

//创建一个串行队列 qos:default
dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_DEFAULT, 0);
    dispatch_queue_t queue = dispatch_queue_create("queue", attr);

//还可以这样创建
//创建一个串行队列 qos:默认 默认default 下面两种一样
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue = dispatch_queue_create("queue", NULL);

DISPATCH_QUEUE_SERIAL 串行。(DISPATCH_QUEUE_SERIAL == NULL) 

DISPATCH_QUEUE_CONCURRENT 并发

任务和队列的组合

同步任务 + 串行队列

//同步 + 串行
    dispatch_queue_t queue = dispatch_queue_create("Queue", NULL);
    NSLog(@"start");
    dispatch_sync(queue, ^{
        NSLog(@"1");
    });
    dispatch_sync(queue, ^{
        NSLog(@"2");
    });
    dispatch_sync(queue, ^{
        NSLog(@"3");
    });
    NSLog(@"end");

想串行队列中添加同步任务

所以顺序执行 输出顺序 start -> 1 -> 2 -> 3 ->end 

  • 同步任务不开启新线程 所以使用当前线程即主线程
  • 同步队列只使用一个线程

同步任务 + 并发队列

//同步 + 并发
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"start");
dispatch_sync(queue, ^{
    NSLog(@"1");
});
dispatch_sync(queue, ^{
    NSLog(@"2");
});
dispatch_sync(queue, ^{
    NSLog(@"3");
});
NSLog(@"end");

所以顺序执行 输出顺序 start -> 1 -> 2 -> 3 ->end 

  • 同步任务不开启新线程 所以使用当前线程主线程
  • 并发队列可以使用多个线程,但是当前只有一个线程可以使用

异步任务 + 串行队列

    //异步 + 串行
    dispatch_queue_t queue = dispatch_queue_create("queue1", NULL);
    NSLog(@"start");
    dispatch_async(queue, ^{
        NSLog(@"1");
    });
    dispatch_async(queue, ^{
        NSLog(@"2");
    });
    dispatch_async(queue, ^{
        NSLog(@"3");
    });
    NSLog(@"end");

只使用一个线程 所以只开启一个线程 在队列中的任务顺序执行  

start 和end在主线程中顺序执行  1 -> 2 -> 3 新线程中顺序执行 具体顺序不定

  • 异步任务可以开启多个线程
  • 串行队列只使用一个线程

异步任务 + 并发队列

    //异步 + 并发
    dispatch_queue_t queue = dispatch_queue_create("queue1", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"start");
    dispatch_async(queue, ^{
        NSLog(@"1");
    });
    dispatch_async(queue, ^{
        NSLog(@"2");
    });
    dispatch_async(queue, ^{
        NSLog(@"3");
    });
    NSLog(@"end");

 start 和end在主线程中顺序执行。1 ,2,3 在新线程中执行 具体开启几个线程由系统决定 执行顺序不确定

主队列和全局队列

主队列: 串行队列 使用主线程 任务 用户操作,比如刷新UI, 用户操作事件(点击,滑动等);   

全局队列:并发队列

  • 异步任务可以开启多个线程
  • 并发队列可以使用多个线程

向主队列中添加同步任务,会造成死锁; 因为同步任务+串行队列 任务完成后才能进行下一个,主队列的任务会和添加到主队列的同步任务相互等待对方完成任务 互不相让导致死锁。

全局队列:不存在死锁情况。

从GCD的角度上说 死锁发生的情况是: 在任务中向该任务所在的任务中添加另一个同步任务

其他使用

dispatch_apply() 并行操作

    dispatch_apply(99, dispatch_get_global_queue(0, 0), ^(size_t i) {
        NSLog(@"%zu", i);
    });
    NSLog(@"end");

输出:0-98不确定顺序 最后end  阻塞当前线程

并发是逻辑上的同时发生,并行更多是侧重于物理上的同时发生

dispatch_queue_create_with_target

在target队列中创建队列

    dispatch_queue_t queue1 = dispatch_queue_create_with_target(nil, DISPATCH_QUEUE_CONCURRENT, dispatch_get_main_queue());
    dispatch_queue_t queue2 = dispatch_queue_create_with_target(nil, DISPATCH_QUEUE_CONCURRENT, dispatch_get_main_queue());
    dispatch_queue_t queue3 = dispatch_queue_create_with_target(nil, DISPATCH_QUEUE_CONCURRENT, dispatch_get_main_queue());
    dispatch_async(queue1, ^{
        NSLog(@"1 start");
        [NSThread sleepForTimeInterval:1.f];
        NSLog(@"1 end");
    });
    
    dispatch_async(queue2, ^{
        NSLog(@"2 start");
        [NSThread sleepForTimeInterval:1.f];
        NSLog(@"2 end");
    });
    dispatch_async(queue3, ^{
        NSLog(@"3 start");
        [NSThread sleepForTimeInterval:1.f];
        NSLog(@"3 end");
    });

结果顺序为 1 start -> 1 end -> 2 start -> 2 end -> 3 start -> 3end

queue1,queue2,queue3 是并发队列 但是dispatch_queue_create_with_target 相当于把 queue1,queue2,queue3放到一个串行队列中执行。

dispatch_set_target_queue

//把第二个参数 堪称targetQueue
void
dispatch_set_target_queue(dispatch_object_t object,
		dispatch_queue_t _Nullable queue);

dispatch_set_target_queue 和上面的dispatch_queue_create_with_target类似

dispatch_set_target_queue  相当于把第一个队列放到第二个队列中执行 相应的队列的优先级向targetQueue看齐

dispatch_queue_t targetQueue = dispatch_queue_create("targetQueue", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue1 = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue2 = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_t queue3 = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);

    dispatch_set_target_queue(queue1, targetQueue);
    dispatch_set_target_queue(queue2, targetQueue);
    dispatch_set_target_queue(queue3, targetQueue);

    dispatch_async(queue1, ^{
        NSLog(@"1 start");
        [NSThread sleepForTimeInterval:1.f];
        NSLog(@"1 end");
    });
    
    dispatch_async(queue2, ^{
        NSLog(@"2 start");
        [NSThread sleepForTimeInterval:1.f];
        NSLog(@"2 end");
    });
    dispatch_async(queue3, ^{
        NSLog(@"3 start");
        [NSThread sleepForTimeInterval:1.f];
        NSLog(@"3 end");
    });

结果顺序为 1 start -> 1 end -> 2 start -> 2 end -> 3 start -> 3end

dispatch_after

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)),                                       dispatch_get_main_queue(), ^{
        NSLog(@"do");
    });
    NSLog(@"end");

延后执行 end -> do

dispatch_barrier_async 异步屏障

    dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"start");
    dispatch_async(queue, ^{
        NSLog(@"1");
    });
    dispatch_async(queue, ^{
        NSLog(@"2");
    });
    dispatch_barrier_async(queue, ^{
        NSLog(@"3-start");
        [NSThread sleepForTimeInterval:1.f];
        NSLog(@"3-end");
    });
    dispatch_async(queue, ^{
        NSLog(@"4");
    });
    dispatch_async(queue, ^{
        NSLog(@"5");
    });
    NSLog(@"end");

log结果 start end在start之后位置。 1 和 2 不确定。3-start -> 3-end 4和5 不确定

dispatch_barrier_async 在同一个队列中 dispatch_barrier_async之前的任务完成后才会执行dispatch_barrier_async中的任务, dispatch_barrier_async完成后才会继续剩下的任务

dispatch_barrier_async 不阻塞当前线程

dispatch_barrier_sync 同步屏障

    dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"start");
    dispatch_async(queue, ^{
        NSLog(@"1");
    });
    dispatch_async(queue, ^{
        NSLog(@"2");
    });
    dispatch_barrier_sync(queue, ^{
        NSLog(@"3-start");
        [NSThread sleepForTimeInterval:1.f];
        NSLog(@"3-end");
    });
    dispatch_async(queue, ^{
        NSLog(@"4");
    });
    dispatch_async(queue, ^{
        NSLog(@"5");
    });
    NSLog(@"end");

log结果 start ->. 1,2 不定 -> 3-start -> 3-end -> 4,5,end 不定

和dispatch_barrier_async 共同点就是 barrier 之前任务完成 进行barrier中的任务 barrier完成后 继续下面的任务

dispatch_barrier_sync 阻塞当前线程 所以end在 dispatch_barrier_sync任务之后

dispatch_queue_set_specific , dispatch_queue_get_specific和dispatch_get_specific

    const void * sepcific = "specific";
    void *context = @"context";
    dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
    dispatch_queue_set_specific(queue, sepcific, context, NULL);
    void *result = dispatch_queue_get_specific(queue, sepcific);
    NSLog(@"%@", result); // log context
    NSLog(@"%@", dispatch_get_specific(sepcific));// log null
    dispatch_async(queue, ^{
        NSLog(@"%@", dispatch_get_specific(sepcific)); // log context
    });

dispatch_queue_set_specific 给队列绑定一个标示 key -> context

dispatch_queue_get_specific 根据key 去除context

dispatch_get_specific 根据key 取出当前block所在队列的 context

dispatch_assert_queue  dispatch_assert_queue_barrier  dispatch_assert_queue_not 

验证current block 是否在是不是在执行在给定的队列上

    dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        //当前block 在 queue中
        dispatch_assert_queue(queue);
    });
    dispatch_barrier_sync(queue, ^{
        //当前 dispatch_barrier_sync 的block 在queue中
        dispatch_assert_queue_barrier(queue);
    });

    //主线程的block 不在queue中
    dispatch_assert_queue_not(queue);

dispatch_group

调度组

    // 创建队列
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
    // 添加异步任务
    dispatch_group_async(group, queue, ^{
        NSLog(@"1");
        [NSThread sleepForTimeInterval:1];
    });
    // 添加异步任务
    dispatch_group_async(group, queue, ^{
        NSLog(@"2");
        [NSThread sleepForTimeInterval:1];
    });
    // 等待 group中任务完成 才会向下执行。阻塞当前线程
    long l = dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    NSLog(@"end %ld",l);
    
    //group中任务完成后 会执行block
    dispatch_group_notify(group, queue, ^{
        NSLog(@"group end");
    });
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
    //手动指出 block 添加到 group中
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"1");
        [NSThread sleepForTimeInterval:1];
        //手动指出 block 中结束
        dispatch_group_leave(group);
    });
    //手动指出 block 添加到 group中
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        NSLog(@"1");
        [NSThread sleepForTimeInterval:1];
        //手动指出 block 中结束
    });
    dispatch_group_notify(group, queue, ^{
       NSLog(@"group end");
    });

dispatch_semaphore 

信号量 线程协调完成特定的事件 管理线程资源

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    dispatch_queue_t queue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
        
    //减少信号量 -1 现在信号量为0 在返回之前如果信号量小于0 dispatch_semaphore_wait会一直等待或直到超时
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    dispatch_async(queue, ^{
        NSLog(@"1 - start");
        [NSThread sleepForTimeInterval:1];
        NSLog(@"1 - end");
        //信号量+1 如果之前信号量小于0 在返回之前则唤起线程
        dispatch_semaphore_signal(semaphore);
    });
    
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    dispatch_async(queue, ^{
        NSLog(@"2 - start");
        [NSThread sleepForTimeInterval:1];
        NSLog(@"2 - end");
        dispatch_semaphore_signal(semaphore);
    });

log 顺序 1 - start -> 1 - end -> 2 - start -> 2 - end

dispatch_source

    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"do");
    });
    dispatch_resume(timer);

猜你喜欢

转载自blog.csdn.net/wangchuanqi256/article/details/89497613