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

2020-04-04  本文已影响0人  JaiUnChat

这时候我们就可以用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的功能设计出发,优雅的使用方法是


作者博客地址

系列文章链接

上一篇下一篇

猜你喜欢

热点阅读