收藏swift

GCD进阶之DispatchWorkItem和DispatchG

2017-10-20  本文已影响1909人  flionel
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中的同步、异步,串行、并行的概念,这样才能记忆深刻。

参考链接

上一篇下一篇

猜你喜欢

热点阅读