美文网首页
iOS 信号量和 Group 的日常使用案例

iOS 信号量和 Group 的日常使用案例

作者: Mr_xuy | 来源:发表于2021-10-29 12:04 被阅读0次

    信号量

    定义

    1、信号量是一种可用来控制访问资源的数量的标识,设定了一个信号量,在线程访问之前,加上信号量的处理,则可告知系统按照我们指定的信号量数量来执行多个线程。
    2、信号量主要的 3 个函数:

    // 创建信号量,参数:信号量的初值,如果小于 0 则会返回 NULL
    dispatch_semaphore_create(信号量值)
    
    // 等待降低信号量
    dispatch_semaphore_wait(信号量,等待时间)
    
    // 提高信号量
    dispatch_semaphore_signal(信号量)
    

    正常使用顺序是先降低然后再提高,这两个函数通常成对使用。

    示例 1:
    /// 信号量,semaphore.wait 会阻塞线程,所以最好放在 .async 中执行,否则会阻塞后续 UI 等任务的执行,造成卡顿。
        func dispatchSignal() {
            let semaphore = DispatchSemaphore(value: 1)
            let queue = DispatchQueue.global(qos: .default)
            queue.async {
                print("--->wait 1")
                _ = semaphore.wait(timeout: .distantFuture)
                print("--->run task 1")
                sleep(1)
                print("--->complete task 1")
                semaphore.signal()
                
                print("--->wait 4")
                _ = semaphore.wait(timeout: .distantFuture)
                print("--->run task 4")
                sleep(1)
                print("--->complete task 4")
                semaphore.signal()
            }
            queue.async {
                print("--->wait 2")
                _ = semaphore.wait(timeout: .distantFuture)
                print("--->run task 2")
                sleep(3)
                print("--->complete task 2")
                semaphore.signal()
            }
            queue.async {
                print("--->wait 3")
                _ = semaphore.wait(timeout: .distantFuture)
                print("--->run task 3")
                sleep(3)
                print("--->complete task 3")
                semaphore.signal()
            }
            print("===============")
        }
    // 输出:
    ===============
    --->wait 2
    --->wait 1
    --->wait 3
    --->run task 2
    --->complete task 2
    --->run task 1
    --->complete task 1
    --->wait 4
    --->run task 3
    --->complete task 3
    --->run task 4
    --->complete task 4
    // 注意:wait1、wait2、wait3 和 === 的输出顺序每次不是固定的。
    
    示例 2:
    override func viewDidLoad() {
        super.viewDidLoad()
        let semaphore = DispatchSemaphore(value: 0)
        test1(semaphore: semaphore)
        test2(semaphore: semaphore)
    }
    func test1(semaphore: DispatchSemaphore) {
            let queue = DispatchQueue.global(qos: .default)
            queue.async {
                print("--->test1_1")
                _ = semaphore.wait(timeout: .distantFuture)
                print("--->test1_2")
                semaphore.signal()
                print("--->test1_3")
            }
        } 
    func test2(semaphore: DispatchSemaphore) {
        print("--->test2_1")
    //        _ = semaphore.wait(timeout: .distantFuture)
        print("--->test2")
    }
    输出:
    --->test2_1
    --->test2
    --->test1_1
    // 注意:由于 semaphore 初始化时设置的值为 0,在 test1 方法中执行了 .wait 方法后,信号量值小于 0,造成该线程卡死,后续方法不再执行。
    
    示例 3:
    /// 使用信号量无序调用接口
        func callApiSignal2() {
            let semaphore = DispatchSemaphore(value: 0)
            let queue = DispatchQueue.global()
            queue.async {
                print("--->callApiSignal2--run task 1")
                sleep(3)
                print("--->callApiSignal2--complete task 1")
                semaphore.signal()
            }
            queue.async {
                print("--->callApiSignal2--run task 2")
                sleep(1)
                print("--->callApiSignal2--complete task 2")
                semaphore.signal()
            }
            queue.async {
                print("--->callApiSignal2--run task 3")
                sleep(4)
                print("--->callApiSignal2--complete task 3")
                semaphore.signal()
            }
            print("--->callApiSignal2--wait 01")
            _ = semaphore.wait(timeout: .distantFuture)
            print("--->callApiSignal2--wait 02")
            _ = semaphore.wait(timeout: .distantFuture)
            print("--->callApiSignal2--wait 03")
            _ = semaphore.wait(timeout: .distantFuture)
            print("--->callApiSignal2--refresh UI")
        }
    // 注意:由于 semaphore 信号量初始化时设定值为 0,当程序执行到主线程的第一个 .wait 方法时,主线程被阻塞了,该线程后续方法不再执行,但不影响上面几个异步线程的执行。
    当某个异步线程中模拟接口调用执行完毕,会执行 semaphore.signal(),从而将信号量值 +1,主线程中对应第一个 .wait 方法收到后线程阻塞被解除,从而会执行后续方法(打印wait 02)。
    输出:
    --->callApiSignal2--wait 01
    --->callApiSignal2--run task 1
    --->callApiSignal2--run task 2
    --->callApiSignal2--run task 3
    --->callApiSignal2--complete task 2
    --->callApiSignal2--wait 02
    --->callApiSignal2--complete task 1
    --->callApiSignal2--wait 03
    --->callApiSignal2--complete task 3
    --->callApiSignal2--refresh UI
    
    示例 4:
    /// 使用信号量有序调用接口
        func callApiSignal1() {
            let semaphore = DispatchSemaphore(value: 0)
            let queue = DispatchQueue.global()
            queue.async {
                print("--->callApiSignal1--run task 1")
                sleep(3)
                print("--->callApiSignal1--complete task 1")
                semaphore.signal()
            }
            print("--->callApiSignal1--wait 01")
            _ = semaphore.wait(timeout: .distantFuture)
            queue.async {
                print("--->callApiSignal1--run task 2")
                sleep(1)
                print("--->callApiSignal1--complete task 2")
                semaphore.signal()
            }
            print("--->callApiSignal1--wait 02")
            _ = semaphore.wait(timeout: .distantFuture)
            queue.async {
                print("--->callApiSignal1--run task 3")
                sleep(4)
                print("--->callApiSignal1--complete task 3")
                semaphore.signal()
            }
            print("--->callApiSignal1--wait 03")
            _ = semaphore.wait(timeout: .distantFuture)
            print("--->callApiSignal1--refresh UI")
        }
    输出:
    --->callApiSignal1--wait 01
    --->callApiSignal1--run task 1
    --->callApiSignal1--complete task 1
    --->callApiSignal1--wait 02
    --->callApiSignal1--run task 2
    --->callApiSignal1--complete task 2
    --->callApiSignal1--wait 03
    --->callApiSignal1--run task 3
    --->callApiSignal1--complete task 3
    --->callApiSignal1--refresh UI
    

    GCD Group 队列组

    示例 1:group 无序调用
    /// 使用 group 无序调用,闭包里是同步方法,可以不使用enter、leave方法
        func callApiGroup1() {
            let group = DispatchGroup()
            let queue = DispatchQueue.global()
            queue.async(group: group, execute: {
                print("--->callApiGroup1--run task1")
            })
            queue.async(group: group, execute: {
                print("--->callApiGroup1--run task2")
            })
            queue.async(group: group, execute: {
                print("--->callApiGroup1--run task3")
            })
            group.notify(queue: queue) {
                print("--->callApiGroup1--notify--run complete")
            }
            queue.async(group: group, execute: {
                print("--->callApiGroup1--run task4")
            })
        }
    --->callApiGroup1--run task1
    --->callApiGroup1--run task4
    --->callApiGroup1--run task2
    --->callApiGroup1--run task3
    --->callApiGroup1--notify--run complete
    
    示例 2:group 无序调用接口进阶版
    /// 使用 group 无序调用接口进阶版,闭包里是异步方法,需要使用enter、leave方法
        func callApiGroup2() {
            let group = DispatchGroup()
            let queue = DispatchQueue.global()
            queue.async(group: group, execute: {
                group.enter()
                // 模拟网络请求
                queue.asyncAfter(deadline: .now() + 4) {
                    print("--->callApiGroup2--run task1")
                    // 通知 group,任务成功完成,要移除,与 enter 成对出现。
                    group.leave()
                }
            })
            queue.async(group: group, execute: {
                group.enter()
                // 模拟网络请求
                queue.asyncAfter(deadline: .now() + 1) {
                    print("--->callApiGroup2--run task2")
                    // 通知 group,任务成功完成,要移除,与 enter 成对出现。
                    group.leave()
                }
            })
            queue.async(group: group, execute: {
                group.enter()
                // 模拟网络请求
                queue.asyncAfter(deadline: .now() + 6) {
                    print("--->callApiGroup2--run task3")
                    // 通知 group,任务成功完成,要移除,与 enter 成对出现。
                    group.leave()
                }
            })
            queue.async(group: group, execute: {
                group.enter()
                // 模拟网络请求
                queue.asyncAfter(deadline: .now() + 10) {
                    print("--->callApiGroup2--run task4")
                    // 通知 group,任务成功完成,要移除,与 enter 成对出现。
                    group.leave()
                }
            })
            queue.async(group: group, execute: {
                group.enter()
                print("--->callApiGroup2--run task5")
                group.leave()
            })
            group.notify(queue: queue) {
                print("--->callApiGroup2--notify--run complete")
            }
        }
    输出:
    --->callApiGroup2--run task5
    --->callApiGroup2--run task2
    --->callApiGroup2--run task1
    --->callApiGroup2--run task3
    --->callApiGroup2--run task4
    --->callApiGroup2--notify--run complete
    
    

    相关文章

      网友评论

          本文标题:iOS 信号量和 Group 的日常使用案例

          本文链接:https://www.haomeiwen.com/subject/vtevaltx.html