博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
swift GCD 的一些高级用法
阅读量:5872 次
发布时间:2019-06-19

本文共 4845 字,大约阅读时间需要 16 分钟。

信号量

之前遇到一个问题,一个请求需要在另一个请求获得的参数。这个时候最开始的办法是把第二个请求写在第一个请求的回调里,但是这样的话,两个请求就很紧密的耦合在一起了。这个时候可以使用信号量来使他们分离开来。 先看下相关的3个方法:

dispatch_semaphore_t dispatch_semaphore_create(long value):方法接收一个long类型的参数, 返回一个dispatch_semaphore_t类型的信号量,值为传入的参数 long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout):接收一个信号和时间值,若信号的信号量为0,则会阻塞当前线程,直到信号量大于0或者经过输入的时间值;若信号量大于0,则会使信号量减1并返回,程序继续住下执行 long dispatch_semaphore_signal(dispatch_semaphore_t dsema):使信号量加1并返回

下面看几种使用方法 保持线程同步

let semaphore = DispatchSemaphore.init(value: 0)        var i = 10        DispatchQueue.global().async {            i = 100                        semaphore.signal()        }        semaphore.wait()        print("i = \(i)")复制代码

输出i = 100 如果注掉semaphore.wait()这一行,则 i = 10 注释: 由于是将block异步添加到一个并行队列里面,所以程序在主线程跃过block直接到semaphore.wait()这一行,因为semaphore信号量为0,所以当前线程会一直阻塞,直到block在子线程执行到semaphore.signal(),使信号量+1,此时semaphore信号量为1了,所以程序继续往下执行。这就保证了线程间同步了。

为线程加锁(同时可以控制最大并发数量 , value 的值等于几就是最多几个并发)

let semaphore = DispatchSemaphore.init(value: 1)        for i in 0..<100 {            DispatchQueue.global().async {                semaphore.wait()                print("i = \(i)")                semaphore.signal()            }                    }复制代码

注释:当线程1执行到semaphore.wait()这一行时,semaphore的信号量为1,所以使信号量-1变为0,并且线程1继续往下执行;如果当在线程1print这一行代码还没执行完的时候,又有线程2来访问,执行semaphore.wait()时由于此时信号量为0(.wait()方法默认时间是 OC 的DISPATCH_TIME_FOREVER),所以会一直阻塞线程2(此时线程2处于等待状态),直到线程1执行完print并执行完semaphore.signal()使信号量为1后,线程2才能解除阻塞继续住下执行。以上可以保证同时只有一个线程执行print这一行代码。

栅栏函数(barrier)

等待异步执行多个任务后, 再执行下一个任务,一般使用barrier函数

//创建串行队列//        let queue = DispatchQueue.init(label: "test", qos: .default, attributes: .init(rawValue: 0), autoreleaseFrequency: .workItem, target: nil)        //创建并行队列        let queue = DispatchQueue.init(label: "test", qos: .default, attributes: .concurrent, autoreleaseFrequency: .workItem, target: nil)                queue.async {
//任务一 for _ in 0...3 { print("......") } } queue.async {
//任务二 for _ in 0...3 { print("++++++"); } } queue.async(group: nil, qos: .default, flags: .barrier) { print("group") } queue.async { print("finish") }最后打印......++++++++++++++++++++++++..................groupfinish复制代码

注释:使用barrier函数可以做到先让前面的任务执行完毕,再执行之后的任务,会阻塞当前的线程

延时任务

let queue = DispatchQueue.init(label: "test", qos: .default, attributes: .concurrent, autoreleaseFrequency: .workItem, target: nil)        queue.async {
//任务一 for _ in 0...3 { print("......") } } print("0") queue.asyncAfter(deadline: DispatchTime.now() + 10, execute: { print("延时提交的任务") }) queue.async {
//任务二 for _ in 0...3 { print("++++++"); } }打印:复制代码

注释10s后提交。并且不会阻碍当前线程

组的用法(Group)

notify(依赖任务)

let queue = DispatchQueue.init(label: "test", qos: .default, attributes: .concurrent, autoreleaseFrequency: .workItem, target: nil)                let group = DispatchGroup()        queue.async(group: group, qos: .default, flags: [], execute: {            for _ in 0...10 {                                print("耗时任务1")            }        })        queue.async(group: group, qos: .default, flags: [], execute: {            for _ in 0...10 {                                print("耗时任务2")            }        })        //执行完上面的两个耗时操作, 回到myQueue队列中执行下一步的任务        group.notify(queue: queue) {            print("回到该队列中执行")        }        queue.async {            print("完成")        }打印:耗时任务2完成耗时任务1耗时任务2耗时任务2耗时任务2耗时任务2耗时任务1耗时任务2耗时任务1耗时任务1耗时任务1耗时任务1回到该队列中执行复制代码

注释:使用group+notify的话,也会等待之前的任务先执行完,和barrier的区别是不会阻碍当前的线程

wait(等待任务)

let queue = DispatchQueue.init(label: "test", qos: .default, attributes: .concurrent, autoreleaseFrequency: .workItem, target: nil)                let group = DispatchGroup()        queue.async(group: group, qos: .default, flags: [], execute: {            for _ in 0...5 {                                print("耗时任务1")            }        })        queue.async(group: group, qos: .default, flags: [], execute: {            for _ in 0...5 {                                print("耗时任务2")            }        })        //等待上面任务执行,会阻塞当前线程,超时就执行下面的,上面的继续执行。可以无限等待 .distantFuture        let result = group.wait(timeout: .now() + 2.0)        switch result {        case .success:            print("不超时, 上面的两个任务都执行完")        case .timedOut:            print("超时了, 上面的任务还没执行完执行这了")        }                print("接下来的操作")打印:耗时任务1耗时任务2耗时任务1耗时任务2耗时任务1耗时任务2耗时任务1耗时任务2耗时任务1耗时任务2耗时任务1耗时任务2不超时, 上面的两个任务都执行完接下来的操作复制代码

注释:使用wait+group的话,如果设置timeout = .distantFuture的话,那么就和barrier函数一样了,会等待之前的完成,否则就是等待之前的完成或者等待设置的时间到了,就会执行接下来的任务了,会阻塞当前现场。

参考: 来自

来自

转载于:https://juejin.im/post/5a9559db5188257a5e5773ad

你可能感兴趣的文章
SVG path
查看>>
js判断checkbox是否选中
查看>>
多系统盘挂载
查看>>
MySQL函数怎么加锁_MYSQL 函数调用导致自动生成共享锁问题
查看>>
MR1和MR2的工作原理
查看>>
Eclipse中修改代码格式
查看>>
GRUB Legacy
查看>>
关于 error: LINK1123: failure during conversion to COFF: file invalid or corrupt 错误的解决方案...
查看>>
python实现链表
查看>>
java查找string1和string2是不是含有相同的字母种类和数量(string1是否是string2的重新组合)...
查看>>
Android TabActivity使用方法
查看>>
Eclipse的 window-->preferences里面没有Android选项
查看>>
《麦田里的守望者》--[美]杰罗姆·大卫·塞林格
查看>>
遇到的那些坑
查看>>
央行下属的上海资信网络金融征信系统(NFCS)签约机构数量突破800家
查看>>
[转] Lazy evaluation
查看>>
常用查找算法总结
查看>>
被神话的大数据——从大数据(big data)到深度数据(deep data)思维转变
查看>>
修改校准申请遇到的问题
查看>>
Linux 进程中 Stop, Park, Freeze【转】
查看>>