GCD进阶之DispatchWorkItem和DispatchGroup

playground-line.jpg

1. DispatchWorkItem简介

DispatchWorkItem是帮助DispatchQueue来执行队列中的任务的,它的初始化方法定义如下代码,

public init(qos: DispatchQoS = default, flags: DispatchWorkItemFlags = default, block: @escaping @convention(block) () -> Swift.Void)

初始化方法可以传入一个闭包,闭包中就是需要执行的任务,通过perform()方法来唤起该DispatchWorkItem来执行任务,

var value = 10
let workItem = DispatchWorkItem {
    value += 5
}
workItem.perform()

1.1 队列中执行DispatchWorkItem的任务

也可以通过队列来同步或异步地执行DispatchWorkItem中的任务,如下代码所示,

let queue = DispatchQueue.global(qos: .utility)

queue.async {
    workItem.perform()
}

当然还可以通过下面的方法来执行,这样代码无疑简洁了很多,

queue.async(execute: workItem)
print("value is \(value)")

1.2 执行结束通过notify提示主队列


workItem.notify(queue: DispatchQueue.main) {
    print("value = ", value)
}
print("value is \(value)")

2 DispatchGroup简介

一个队列执行多个任务或多个队列执行不同任务,怎样知道所有的任务都执行完毕呢,这时可以使用DispatchGroup来解决这个需求。

2.1 创建DispatchGroup,将队列加入Group

let queue = DispatchQueue(label: "com.flion.dispatchgroup", attributes: .concurrent)
let group = DispatchGroup()

// group.enter()
queue.async(group: group) {
    print("doing stuff")
//    group.leave()
}

//group.enter()
queue.async(group: group) {
    print("doing more stuff again")
//    group.leave()
}

2.2 所有任务执行结束,通过notify提示主线程

group.notify(queue: Dispatch.main) {
    print("done doing all stuff")
}

3 GCD的应用场景以及思考

GCD的概念相对较多,使用也很灵活,在使用过程中应该避免线程死锁,以下笔者根据自己的业务场景总结的一些使用经验,如有错误,还请指正,

3.1 多个任务需要需要依次执行

例如先打开冰箱塞入食品关上冰箱,此时可以将这些任务放入串行队列中执行,如下代码所示,

let serialQueue = DispatchQueue(label: "com.flion.serialQueue", qos: .default)
serialQueue.async {
    print("打开冰箱")
}

serialQueue.async {
    print("塞入食品")
}

serialQueue.async {
    print("关上冰箱")
}

3.2 多个任务执行完成之后再执行后续代码

例如,煮饭、烧开水、做4道小菜,吃饭,煮饭和烧开水可以靠电器来执行,做菜需要靠我自己来做,那么这3件事情是可以同时进行的,只有这3件事情做完才可以开始吃饭,可以将这3件事情放入并行队列,并通过DispatchGroup来执行,如下代码所示,

let group = DispatchGroup()
let queue1 = DispatchQueue(label: "com.flion.queue1", qos: .default, attributes: .concurrent)
queue1.async(group: group) {
    print("烧开水")
    Thread.sleep(forTimeInterval: 2)
}
        
queue1.async(group: group) {
    print("煮米饭")
    Thread.sleep(forTimeInterval: 2)
}
        
queue1.async(group: group) {
    print("做4道小菜")
    Thread.sleep(forTimeInterval: 2)
}

group.notify(queue: DispatchQueue.main) {
    print("开始吃饭喽")
}

当然也可以创建3个队列,并通过DispatchGroup来执行,执行结束之后notify提示主线程,

let group = DispatchGroup()
let queue1 = DispatchQueue(label: "com.flion.queue1", qos: .default, attributes: .concurrent)
queue1.async(group: group) {
    print("烧开水")
    Thread.sleep(forTimeInterval: 2)
}
        
let queue2 = DispatchQueue(label: "com.flion.queue1", qos: .default, attributes: .concurrent)
queue2.async(group: group) {
    print("煮米饭")
    Thread.sleep(forTimeInterval: 2)
}
        
let queue3 = DispatchQueue(label: "com.flion.queue1", qos: .default, attributes: .concurrent)
queue3.async(group: group) {
    print("做4道小菜")
    Thread.sleep(forTimeInterval: 2)
}
        
group.notify(queue: DispatchQueue.main) {
    print("开始吃饭喽")
}

3.3 再说一说DispatchWorkItem

读者可以看到,在上面的开冰箱吃饭的代码中并没有使用DispatchWorkItem,在我看来使用WorkItem可以使代码更加简洁,它将业务内聚,将模块分离。当然也可以完全不适用WorkItem,这看开发者的喜好了。

GCD的使用非常灵活,读者朋友应该多多尝试,深入理解GCD中的同步、异步,串行、并行的概念,这样才能记忆深刻。

参考链接

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1. GCD简介 什么是GCD呢?我们先来看看百度百科的解释简单了解下概念 引自百度百科:Grand Centra...
    千寻_544f阅读 402评论 0 0
  • 多线程 在iOS开发中为提高程序的运行效率会将比较耗时的操作放在子线程中执行,iOS系统进程默认启动一个主线程,用...
    郭豪豪阅读 2,617评论 0 4
  • 41.多用派发队列,少用同步锁 在Objective-C中,如果有多个线程要执行同一份代码,那么有时可能会出问题。...
    Code_Ninja阅读 1,173评论 1 13
  • Speaker: Dan Buettner Key words: longevity social connect...
    TedDigger阅读 661评论 0 0
  • 天天浮世绘 看了一会读报新闻 又与朋友感叹的聊了一会 人的思维和格局也决定了人的思想和层次 而衣品和个性,也决定了...
    单品姑娘阅读 181评论 0 0