将来跳槽用

[need fix]GCD (Grand Central Dis

2021-08-31  本文已影响0人  helinyu

GCD概要

3.3.1 什么是GCD
image.png

PS : GCD 使用了简介的记述方式实现了复杂繁琐的多线程编程。

到引入GCD之前, cocoa只给你在NSObject类中实现了有关的多线程变成技术。 perform... 有关的方法。


FOUNDATION_EXPORT NSNotificationName const NSWillBecomeMultiThreadedNotification;
FOUNDATION_EXPORT NSNotificationName const NSDidBecomeSingleThreadedNotification;
FOUNDATION_EXPORT NSNotificationName const NSThreadWillExitNotification;  // 可以用来监听线程是否已经销毁了?
// 测试, 发现我们在iOS上的环境,只有最后一个通知会收到,大概是因为app启动的时候就已经是多线程了。
线程的通知。
@interface NSObject (NSThreadPerformAdditions)

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
    // equivalent to the first method with kCFRunLoopCommonModes
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
// 主线程、 后台线程

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
// 线程的后向方式,执行在哪个生成的子线程里面。
    // equivalent to the first method with kCFRunLoopCommonModes
@end

PS: perforSelector 系方法确实要比使用NSThread 类精心多线程编程简单。 当时相比GCD,GCD更加的简介。

没有多线程的程序执行示意图
多线程执行示意图
多线程的问题

iOS为什么需要多线程?

可保证应用程序的响应性能。
因为主线程是渲染UI ,触摸屏幕时间等。 不能够妨碍主线程的循环执行刷新等等。


3.2 GCD 的API

3.2.1 dispatch queue (队列)

定义:开发者要做的只是定义想要执行的任务并追加到适当的 dispatch queue 中。

// 基本执行的结构
  dispatch_async(queue, ^{
           // 想执行的任务
        });

dispatch queue :执行处理的等待队列。
block:block 语法中记述想之心的处理并将其追加大搜dispatch queue 中。
追加顺序: FIFO

dispatch queue 分类:
serial dispatch queue 串行 (等待上一个任务完成)
concurrent dispatch queue 并行 (不用等待上一个任务完成)


两种队列的差异
两种队列示意图

并行队列,可以让多个任务同时执行。 但并行执行的处理数量取决于当前系统的状态。 iOS基于dispatch queue 中的处理数、cpu核数以及cpu负荷等当前系统的状态决定concurrent dispatch queue 中并行执行的处理数。
所谓“并行执行”, 就是使用多个线程同事执行多个处理。

(1)iOS核心 —— XNU 内核决定应当使用的线程数,并只能生成所需的线程执行处理。
(2)当处理结束, 应当执行的处理数减少时, XNU内核会结束不再需要的线程。
(3)XNU内核仅使用concurrent dispatch queue 便可完美地管理并执行多个处理的线程。

在不想改变执行的处理顺序或不想并行之心多个处理时
—— serial dispatch queue

dispatch_queue_create
    decodeQue = dispatch_queue_create("KMLoadingImageViewDecodeQueue", DISPATCH_QUEUE_SERIAL);
创建了一个并行的队列


串行队列可以让线程安全

生成队列并使用
好像现在并不需要程序员进行释放这个内容

Main dispatch queue 、global dispatch queue
Main dispatch queue : 主线程队列 (serial)



global dispatch queue : 全局线程 (concurrent dispatch queue)


3.2.4 dispatch_set_target_queue
这样,就可以第二个队列的任务执行在第一个任务的后面
  dispatch_queue_t serialQueue1 = dispatch_queue_create("com.gcd.setTargetQueue2.serialQueue1", NULL);
        dispatch_queue_t serialQueue2 = dispatch_queue_create("com.gcd.setTargetQueue2.serialQueue2", NULL);
        dispatch_queue_t serialQueue3 = dispatch_queue_create("com.gcd.setTargetQueue2.serialQueue3", NULL);
        dispatch_queue_t serialQueue4 = dispatch_queue_create("com.gcd.setTargetQueue2.serialQueue4", NULL);
        dispatch_queue_t serialQueue5 = dispatch_queue_create("com.gcd.setTargetQueue2.serialQueue5", NULL);

        //创建目标串行队列 ,也就是将哪些队列放到这个队列里面执行
        dispatch_queue_t targetSerialQueue = dispatch_queue_create("com.gcd.setTargetQueue2.targetSerialQueue", NULL);
        
        //设置执行阶层
        dispatch_set_target_queue(serialQueue1, targetSerialQueue);
        dispatch_set_target_queue(serialQueue3, targetSerialQueue);
        dispatch_set_target_queue(serialQueue2, targetSerialQueue);
        dispatch_set_target_queue(serialQueue4, targetSerialQueue);
        dispatch_set_target_queue(serialQueue5, targetSerialQueue);
        
        dispatch_async(serialQueue1, ^{
            NSLog(@"1");
        });
        dispatch_async(serialQueue2, ^{
            NSLog(@"2");
        });
        dispatch_async(serialQueue3, ^{
            NSLog(@"3");
        });
        dispatch_async(serialQueue4, ^{
            NSLog(@"4");
        });
        dispatch_async(serialQueue5, ^{
            NSLog(@"5");
        });
// 即为将那5个队列,合并到同一个队列里面
3.2.5 dispatch_after 追加时间处理
      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
           block();
       });
PS:0.3秒后执行内容
3.2.6 dispatch group [常用]

可以和group有关的方法进行使用。


dispatch_group 就是这么几个方法,可以混合使用
3.2.7 dispatch_barrier_async 栅栏

实现了一个变量的读取的线程安全。 和读写锁有类似的功能。




上图对应的代码

这个方法还会实现,有关的一个变量安全读写的的线程安全问题。就是和上面的共享数据的读写问题。

3.2.8 dispatch_sync 同步的方法,没有开启线程能力。

注意造成死锁。
如果一个并发队列中,有async使用,也有意对应的async使用。 那么这个将会如何处理?
// 并发队列不要求上一个任务完成再执行, 而sync是要求上一个任务完成之后再执行。


3.2.9 dispatch_apply
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
        dispatch_apply(10, queue, ^(size_t index) {
            NSLog(@"lt - index:%zd",index);
        });
        NSLog(@"done ");
执行结果
为什么这个方法很少用到?

对于批量处理相同的任务dispatch_apply 相较于 for 和 while 能更合理的使用资源
当时iOS中,里面就有了一个并发的遍历方式了;

上面的方法应该是使用下面的方法实现的 这个可能在定时GCD实现的定时器也是使用到的
3.2.11 dispatch semaphore 信号量处理 【常用】

可以说是比serial queue 以及dispatch_barrier_aync 方法更加细粒度进行控制的。

3.2.12 dispatch_once 【常用】

保证在应用程序执行中只执行一次指定处理的API。

3.2.13 dispatch I/O

提高文件的读写速度
GCD 有效读取数千个小文件

3.3 GCD 的实现 —— 这个底层内容实现,先不管。

3.3.1 dispatch queue


可以查看源码,看看以后怎么编译这个源码的内容, 然后进行调用这个东西

3.3.2 dispatch source








有关具体的方法, 可以去看一下libdispatch 这个库的内容。

GCD 上面的队列

上一篇下一篇

猜你喜欢

热点阅读