美文网首页
Swift多线程开发 - 3. DispatchGroup和Se

Swift多线程开发 - 3. DispatchGroup和Se

作者: JaiUnChat | 来源:发表于2020-04-04 10:55 被阅读0次

    这时候我们就可以用DispatchGroup来处理

    DispatchGroup

    基础使用,追踪不同队列中的任务。

    不同队列可以用来分别处理不同优先级的任务

    let group = DispatchGroup()
    
    someQueue.async(group: group) { ... 一些任务 ... }  
    someQueue.async(group: group) { ... 一些任务 .... }  
    someOtherQueue.async(group: group) { ... 其它任务 ... }  
    
    // 任务全部完成之后会在指定的队列执行
    group.notify(queue: DispatchQueue.main) { [weak self] in
        guard let self = self else { return }
        self.textLabel.text = "全部任务完成" 
    }
    
    

    wait

    let group = DispatchGroup()
    let queue = DispatchQueue.global(qos: .userInitiated)
    
    queue.async(group: group) {
        print("开始任务1")
        Thread.sleep(until: Date().addingTimeInterval(4)) // a
        print("结束任务1")
    }
    
    queue.async(group: group) {
        print("开始任务2")
        Thread.sleep(until: Date().addingTimeInterval(2)) // b
        print("结束任务2")
    }
    
    if group.wait(timeout: .now() + 5) == .timedOut { // c
        print("啊!我等不下去了!😭")
    } else {
        print("所有任务都已经完成😌")
    }
    
    
    

    上述代码会输出

    开始任务1
    开始任务2
    结束任务2
    结束任务1
    所有任务都已经完成😌
    

    如果你把注释a的4秒改成6秒,则会输出

    开始任务1
    开始任务2
    结束任务2
    啊!我等不下去了!😭
    结束任务1
    

    注意输出的结束任务1, wait只是设置了一个阈值来监测任务会不会在规定的时间内完成,并不会停止还未完成的任务

    注意,wait 会阻塞当前线程,所以千万不要在主线程调用

    enter()leave()

    Dispatch队列会在闭包内的代码执行完的时候自动通知DispatchGroup.
    但是如果你在Dispatch闭包里调用了一个异步请求,问题就来了,Dispatch内的代码很有可能在异步请求完成之前就跑完了,然后就告诉Group"这里的任务已经完成了", 但实际并不符合我们的期望。
    这时候,我们就可以用group.enter()group.leave()来控制。
    这对命令其实就相当于是在计数,当你enter()的时候,运行中的任务计数+1; 当你leave()的时候,运行中的任务-1。

    queue.dispatch(group: group) {
        // count = 1
        group.enter()
        // count = 2
        someAsyncMethod {
            // 知行业务逻辑
            group.leave() // count -= 1
        } 
        // count -= 1
    }
    
    

    Semaphore

    当需要对每个资源精确地限制访问量的时候就可以用Semaphore(信号量)了

    假设现在有个批量下载任务,你最多允许3个下载任务同时进行

    先创建一个只最多允许三个访问的Semaphore

      let semaphore = DispatchSemaphore(value: 3)
    

    模拟10个下载任务

    for i in 1...10 { 
        queue.async(group: group) {
            semaphore.wait() // Semaphore计数+1
            print("正在下载第\(i)张图")
            // 模拟网络等待
            Thread.sleep(forTimeInterval: 2) 
            print("第\(i)张图已下载")
            semaphore.signal() // Semaphore计数-1
        } 
    }
    

    上述代码你会一下子看到

    “正在下第1张图”
    “正在下第2张图”
    “正在下第3张图”
    

    然后直到2秒后,下载任务才会继续执行

    小结

    从代码实现的角度,对于某些业务逻辑,比如下载10张图片完成后刷新界面,上述两种方法都可以达到,但是从Dispatch的功能设计出发,优雅的使用方法是

    • DispatchGroup用于跟踪任务完成状态,然后在批量任务完成/未完成的时候来处理业务逻辑
    • DispatchSemorephore用于控制访问数量

    作者博客地址

    系列文章链接

    相关文章

      网友评论

          本文标题:Swift多线程开发 - 3. DispatchGroup和Se

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