GCD相关


title: GCD相关
date: 2019-09-11 10:58:45
tags:

记得之前面试的时候遇到一个问题,一个tableview需要请求多个接口展示数据,如何避免卡顿,当时不太清楚,这里就总结一下GCD相关的一些东西。

#1.简介

GCD是iOS多线程的一种实现方式,GCD会自动管理线程的生命周期,程序员只要告诉GCD要执行什么任务,不需要编写任何线程管理代码

#2.任务

任务就是你在线程中执行的那段代码

#3.队列

GCD有三种队列

3.1主队列

主队列作用跟主线程一样,是串行队列,可通过下面代码获取

let mainQueue = DispatchQueue.main
dispatch_queue_t mainQueue = dispatch_get_main_queue();

3.2全局并发队列

let globalQueue = DispatchQueue.global(qos: DispatchQoS.QoSClass.default)

优先级 userInteractive>default>unspecified>userInitiated>utility>background

dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 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

3.3创建队列

let customQueue = DispatchQueue(label: "haha", qos: .default)串行
 let customQueue = DispatchQueue(label: "哈哈", qos: .default, attributes: .concurrent)//并发

attributes 默认是串行队列 .concurrent并发队列

  dispatch_queue_t customQueue = dispatch_queue_create("哈哈", DISPATCH_QUEUE_SERIAL);

第二个参数 DISPATCH_QUEUE_SERIAL 表示串行队列,DISPATCH_QUEUE_CONCURRENT 表示并发队列。

3.3.1dispatch_set_target_queue
dispatch_set_target_queue(dispatch_object_t object, dispatch_queue_t queue);

*第一个参数是要执行变更的队列(不能指定主队列和全局队列)
第二个参数是目标队列(指定全局队列),执行变更的队列优先级跟目标队列变为一样,

链接 https://www.jianshu.com/p/1945f4b8b203

3.4串行队列和并发队列

  • 串行队列 :每次只有一个任务被执行。让任务一个接着一个地执行。(只开启一个线程,一个任务执行完毕后,再执行下一个任务)
  • 可以让多个任务并发(同时)执行。
  • 并发队列的并发功能只有在异步(dispatch_async)函数下才有效

#4.任务的创建方法

globalQueue.async { }
globalQueue.sync {      }

同步任务不具备开启新线程的能力

4.1同步执行+并发队列

所有任务都是在当前线程(主线程)中执行的,没有开启新的线程

任务按顺序执行的

只有当前线程这一个线程(同步任务不具备开启新线程的能力),所以也就不存在并发

4.2异步执行 + 并发队列

可以开启多个线程,任务交替(同时)执行

异步执行不会做任何等待,可以继续执行任务

4.3同步执行 + 串行队列

所有任务都是在当前线程(主线程)中执行的,并没有开启新的线程(同步任务不具备开启新线程的能力

串行队列每次只有一个任务被执行,任务一个接一个按顺序执行

4.4异步执行 + 串行队列

开启了一条新线程(异步执行具备开启新线程的能力,串行队列只开启一个线程)

异步执行不会做任何等待,可以继续执行任务

任务是按顺序执行的(串行队列每次只有一个任务被执行,任务一个接一个按顺序执行)

4.5同步执行 + 主队列

4.5.1在主线程中调用

会造成死锁,并且会奔溃

4.5.2在其他线程中调用

Thread.detachNewThread {}

跟 同步执行 + 串行队列 结果一样

4.6异步执行 + 主队列

跟 异步执行 + 串行队列 结果一样

#5.GCD其他方法

5.1barrier栅栏方法

Swift

let customQueue = DispatchQueue(label: "haha", qos: .default, attributes: .concurrent)

customQueue.async(flags: .barrier) {

            for _ in  0..<2 {

                Thread.sleep(forTimeInterval: 2)

                print("barrier--\(Thread.current)")

            }
}

OC

dispatch_queue_t queue = dispatch_queue_create("haha", DISPATCH_QUEUE_CONCURRENT);

dispatch_barrier_async(queue, ^{    });

代码执行顺序: barrier前面的代码 ->barrier代码->barrier后面的代码

5.2延时执行

swift

func** after() {

        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {

            print("2秒后执行")

        }
 }

OC

dispatch_after(dispatch_time(DISPATCH_WALLTIME_NOW, 2), dispatch_get_main_queue(), ^{
        NSLog(@"两秒后执行");
});

5.2+定时器

Swift

var timer: DispatchSourceTimer?
func timerResume() {
        self.timer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main)
        timer?.schedule(deadline: .now(), repeating: 1)
        timer?.setEventHandler {
            DispatchQueue.main.async {[**weak** **self**] **in**
                self?.timerCount()
            }
        }
        timer?.resume()
    }    
    func timerCount() {
        self.count += 1
        print(self.count)
        if self.count == 10 {
            self.timer?.cancel()
        }
    }

5.3dispatch_once一次性代码

dispatch_once 函数能保证某段代码在程序运行过程中只被执行1次,并且即使在多线程的环境下,dispatch_once也可以保证线程安全

OC中创建单例的时候可以用到

+(id)shareInstance {
    static ViewController2 *shareInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        shareInstance = [[ViewController2 alloc]init];
    });
    return shareInstance;
}

Swift 中已经没有dispatch_once,static背后已经实现了dispatch_once

单例这样写**static** **let** shareInstance = NetworkApi()

5.4dispatch_apply快速迭代

*如果是在串行队列中使用 dispatch_apply,那么就和 for 循环一样,按顺序同步执行

*可以利用并发队列进行异步执行,dispatch_apply 可以 在多个线程中同时(异步)遍历多个数字。

*dispatch_apply 都会等待全部任务执行完毕,才会进行其他操作

Swift

DispatchQueue.concurrentPerform(iterations: 6) { (index) in

            print("\(index),\(Thread.current)")

        }

oc

dispatch_queue_t customQueue = dispatch_queue_create("haha", DISPATCH_QUEUE_CONCURRENT);

    dispatch_apply(6, customQueue, ^(size_t index) {

        NSLog(@"%zu", index);

    });

5.5dispatch_group队列组

5.5.1dispatch_group_notify

监听 group 中任务的完成状态,当所有的任务都执行完成后,追加任务到 group 中,并执行任务

Swift

let group = DispatchGroup()
let globalQueue = DispatchQueue.global(qos: .default)
globalQueue.async(group: group, qos: .default, flags: DispatchWorkItemFlags(rawValue: 0)) {
    for _ in 0..<2 {
        Thread.sleep(forTimeInterval: 2)
        print("1..\(Thread.current)")
    }
}
globalQueue.async(group: group, qos: .default, flags: DispatchWorkItemFlags(rawValue: 0)) {
   for _ in 0..<2 {
        Thread.sleep(forTimeInterval: 2)
        print("2..\(Thread.current)")
    }
}
group.notify(queue: DispatchQueue.main) {
    for _ in 0..<2 {
        Thread.sleep(forTimeInterval: 2)
        print("3..\(Thread.current)")
    }
}

执行结果

1..<NSThread: 0x600002010800>{number = 3, name = (null)}
2..<NSThread: 0x60000201c080>{number = 4, name = (null)}
1..<NSThread: 0x600002010800>{number = 3, name = (null)}
2..<NSThread: 0x60000201c080>{number = 4, name = (null)}

3..<NSThread: 0x600002072c80>{number = 1, name = main}
3..<NSThread: 0x600002072c80>{number = 1, name = main}

oc

dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, globalQueue, ^{
    for (int i; i <3; i ++) {
        [NSThread sleepForTimeInterval:2];
        NSLog(@"1...%@",[NSThread currentThread]);
    }
});    
dispatch_group_async(group, globalQueue, ^{
    for (int i; i <3; i ++) {
        [NSThread sleepForTimeInterval:2];
        NSLog(@"2...%@",[NSThread currentThread]);
    }
});    
dispatch_group_notify(group, globalQueue, ^{
    [NSThread sleepForTimeInterval:2];
    NSLog(@"notify... %@",[NSThread currentThread]);
});
5.5.2dispatch_group_wait

暂停当前线程(阻塞当前线程),等待指定的 group 中的任务执行完成后,才会往下继续执行,会阻塞当前线程

Swift4

let group = DispatchGroup()
print("groupBegin")
let globalQueue = DispatchQueue.global(qos: .default)
globalQueue.async(group: group, qos: .default, flags: DispatchWorkItemFlags(rawValue: 0)) {
    for _ in 0..<2 {
        Thread.sleep(forTimeInterval: 2)
        print("1..\(Thread.current)")
    }
}
globalQueue.async(group: group, qos: .default, flags: DispatchWorkItemFlags(rawValue: 0)) {
    for _ in 0..<2 {
        Thread.sleep(forTimeInterval: 2)
        print("2..\(Thread.current)")
    }
}
group.wait()
print("groupEnd")
groupBegin
2..<NSThread: 0x6000038af640>{number = 3, name = (null)}
1..<NSThread: 0x60000389e780>{number = 4, name = (null)}
2..<NSThread: 0x6000038af640>{number = 3, name = (null)}
1..<NSThread: 0x60000389e780>{number = 4, name = (null)}
groupEnd

oc

dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
NSLog(@"group begin");
dispatch_group_async(group, globalQueue, ^{
    for (int i; i <3; i ++) {
        [NSThread sleepForTimeInterval:2];
        NSLog(@"1...%@",[NSThread currentThread]);
    }
});
dispatch_group_async(group, globalQueue, ^{
    for (int i; i <3; i ++) {
        [NSThread sleepForTimeInterval:2];
        NSLog(@"2...%@",[NSThread currentThread]);
    }
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"group end");

5.6dispatch_semaphore

*dispatch_semaphore_create:创建一个 Semaphore 并初始化信号的总量

*dispatch_semaphore_signal:发送一个信号,让信号总量加 1

*dispatch_semaphore_wait:可以使总信号量减 1

*如果一个动作尝试减少信号量的值,使其小于0,那么这个动作将会被阻塞,直到有其他调用者(在其他线程中)增加该信号量的值。

*通常用作线程同步,保证线程安全

swift

let queue = DispatchQueue.global(qos: .default)
let semaphore = DispatchSemaphore(value: 1)
for i in 0..<100 {
    queue.async {
        semaphore.wait(timeout: DispatchTime.distantFuture)
        print("i=\(i)")
        semaphore.signal()
    }
}

oc

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
dispatch_async(queue, ^{
    for (int i = 0; i < 100; i ++) {
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"i = %d", i);
        dispatch_semaphore_signal(semaphore);
    }
});

参考链接

https://www.jianshu.com/p/2d57c72016c6

https://www.jianshu.com/p/43d6785d97c2

https://developer.apple.com/documentation/dispatch

https://www.jianshu.com/p/7ee4a38c9e27

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值