美文网首页Swift
Swift3.0 DispatchQueue-对GCD的改写

Swift3.0 DispatchQueue-对GCD的改写

作者: Supremodeamor | 来源:发表于2017-04-21 15:38 被阅读207次

在iOS中使用多线程的技术包括NSTread、NSOperationQueue、Grand Central Dispatch(GCD) 三种。NSThread继承于NSObject类,创建方法略显繁琐,且是在ObjectIve-C中使用的。NSOperationQueue是对GCD的面向对象的封装,在日常开发中,GCD是最为快捷简便的,也是我日常使用最多的,而在Swift3.0中,基于 Swift语法封装的DispatchQueue给Swift带来了更为方便的使用,今天就来扒一扒这个DispatchQueue

DispatchQueue-基本概念

一、串行和并发

DispatchQueue 即执行任务的队列,分为串行队列(Serial Dispatch Queue)和并发队列(Concurrent Dispatch Queue)。串行队列中的任务是顺序执行的,即先放进去的任务先执行,后放入的人物后执行。并发队列的任务则可以在后台中一起执行。

二、同步和异步

同步(sync)和异步(async)的概念很容易和串行并发的概念混淆,这里特别说明一下:同步异步是线程之间的执行方式,串行并发是单一队列内多个任务的执行方式。
可以先看个案例:

override func viewDidLoad() {
        super.viewDidLoad()
    
        let queue1: DispatchQueue = DispatchQueue(label: "com.artron.myqueue")
       let queue2: DispatchQueue = DispatchQueue(label: "com.artron.myqueue")
        queue1.sync {
            for i in 0..<10 {
                print("🌧", i)
            }
        }
        queue2.async {
            for i in 10..<20 {
                print("🔥", i)
            }
        }
        for i in 100..<110 {
            print("💧", i)
        }
}

viewDidLoad方法,也就是主线程中,创建任务队列,先同步遍历,再异步遍历,然后再主线程遍历,看下运行结果:

先同步后异步

下面再看下先异步后同步的情况:

override func viewDidLoad() {
        super.viewDidLoad()
    
        let queue1: DispatchQueue =     DispatchQueue(label: "com.artron.myqueue")
       let queue2: DispatchQueue =     DispatchQueue(label: "com.artron.myqueue")
        queue1.async {
            for i in 10..<20 {
                print("🔥", i)
            }
        }
        queue2.sync {
            for i in 0..<10 {
                print("🌧", i)
            }
        }
        for i in 100..<110 {
            print("💧", i)
        }
    }
先异步后同步

两个实验结果可以得出结论:
1,同步执行时,只有该队列内任务完成时,才会执行下一个队列;
2,异步执行时并不影响下一个队列的执行。
那么为什么会出现这两种不同的方式呢?也就是二者的使用情景有什么不同?
异步执行因其不阻塞主线程,可以将任务周期长(如网络请求)、CPU占用率高的操作放在后台执行。而当不同线程需要操作相同变量时,为了避免发生数据操作冲突和危险,同步线程就可以派上用场了。

3,任务项(WorkItem)

任务项就是代码块,即队列里要执行的任务代码,一个队列里可以有多个任务项,任务项之间的执行方式就是或串行、或并发。

4,优先级和Quality of Service (Qos)

除了简单的同步异步影响队列的执行,优先级会直接决定队列的执行顺序。queueWithQos()包含了队列的重要程度和优先级信息,Swift中用枚举描述:

/// qos_class_t
public struct DispatchQoS : Equatable {

    public let qosClass: DispatchQoS.QoSClass

    public let relativePriority: Int

    public static let background: DispatchQoS

    public static let utility: DispatchQoS

    public static let `default`: DispatchQoS

    public static let userInitiated: DispatchQoS

    public static let userInteractive: DispatchQoS

    public static let unspecified: DispatchQoS

    public enum QoSClass {

        case background

        case utility

        case `default`

        case userInitiated

        case userInteractive

        case unspecified

        public init?(rawValue: qos_class_t)

        public var rawValue: qos_class_t { get }
    }

  public init(qosClass: DispatchQoS.QoSClass, relativePriority: Int)
}

优先级顺序:userInteractive> userInitiated> default> utility> background> unspecified

以上概念理解之后,再使用DispatchQueue就很容易了。

DispatchQueue-API解析

  1. 便利构造器

    public convenience init(label: String, qos: DispatchQoS = default, attributes: DispatchQueue.Attributes = default, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency = default, target: DispatchQueue? = default)
    

参数解释:
label: 队列名称,最好是写有意义名字,能一看就知道这个队列要执行什么任务;
qos: 队列重要性和优先级(.userInteractive .userInitiated .default .utility .background .unspecified)
attributes: 可填写两个属性:.concurrent表明队列是并发队列,.initiallyInactive表明队列需要手动开启。不填写时默认队列串行、自动执行。
autoreleaseFrequency: 官方文档是说当设为.workItem时,所有异步任务提交的代码块会被封装成独立的任务,在同步执行的队列则不受影响。
target : 目标队列
后两个参数的意义我还不太理解,希望有人看到可以指教一下。
示例:

let autoQueue: DispatchQueue = DispatchQueue(label: "defaultQueue", qos: .userInitiated)
    autoQueue.async {
        print("I will auto activate")
    }
    
let initiallyInactiveQueue : DispatchQueue = DispatchQueue(label: "initiallyInactiveQueue", qos: DispatchQoS.userInitiated, attributes: [.concurrent, .initiallyInactive])
    initiallyInactiveQueue.async {
        print("I need be activate manual")
    }
    initiallyInactiveQueue.activate()

注:手动开始线程是为了在特定场景下执行特定任务,此处只是为了演示用法。

2.执行方法

public func sync(execute workItem: DispatchWorkItem),
public func async(execute workItem: DispatchWorkItem),
public func sync(execute block: () -> Swift.Void),
public func async(execute block: () -> Swift.Void)

这四个方法其实就是两个方法,只不过一个是直接执行block代码,一个是执行任务项。同样的延迟执行方法如下:

public func asyncAfter(deadline: DispatchTime, execute: DispatchWorkItem),
public func asyncAfter(deadline: DispatchTime, qos: DispatchQoS = default, flags: DispatchWorkItemFlags = default, execute work: @escaping @convention(block) () -> Swift.Void)

    let delayQueue = DispatchQueue(label: "delayQueue");
    // 延迟2s执行
    delayQueue.asyncAfter(deadline: .now() + .seconds(2)) { 
        print(Date())
    }

3.DispatchGroup
DispatchGroup就是把队列放到一个组里统一管理,这些队列执行的任务一般是有关联的,示例:

    let group = DispatchGroup()
    let queue1 = DispatchQueue(label: "work1")
    queue1.async(group: group) {
        print("干完work1")
        sleep(2)
    }
    group.wait()
    let queue2 = DispatchQueue(label: "work2")
    queue2.async(group: group){
        print("干完work2")
    }
    group.notify(queue: DispatchQueue.main) {
        print("都干完了,可以下班了")
    }

分析:queue1queue2是异步执行的两个队列,queue1中令系统沉睡2s,方法group.wait()的作用是让queue1执行完毕后再执行后续队列(这里是queue2),否则queue2异步执行。
group.notify()方法是在group内的队列都执行完毕后才会执行。

4,获取主线程队列

 let mainQueue = DispatchQueue.main
 mainQueue.async { 
        print("其实还是主线程")
    }

5,全局队列

DispatchQueue.global().async {
    print("全局队列")
}

相关文章

  • Swift3.0 DispatchQueue-对GCD的改写

    在iOS中使用多线程的技术包括NSTread、NSOperationQueue、Grand Central Dis...

  • swift中GCD的使用详情

    想看swift3.0使用GCD,请点击GCD详解 想看swift3.0闭包的使用和介绍,请点击Swift版闭包使用...

  • GCD 在 Swift 中的用法

    DispatchQueue Swift 中,对 GCD 语法进行了彻底改写。引入了 DispatchQueue 这...

  • iOS多线程-GCD(Swift)

    GCD准确的来讲应该叫做并发编程技术,因为swift3.0后GCD使用方式有很大的变化这里用Swift来重新整理一...

  • swift3.0 GCD

    随着苹果推出swift3.0,很多API都发生了变化,下面我就来总结下GCD的一些常用API用法。 首先为了方便先...

  • swift3.0 -- GCD

    1. 自己创建队列 2. 全局队列的一些说明 3. 获取一个队列 我们使用 DispatchQueue.globa...

  • Swift3.0 中的GCD

  • swift3.0 GCD的使用

    取消过去的接口 说起 GCD, 大家肯定回想起类似 dispatch_async 这样的语法,这个语法在swift...

  • Swift3.0中的GCD

    swift 3中对C层级的GCD的API进行了彻头彻尾的改变。本文将从实际使用场景来了解一下新的api使用。 di...

  • swift3.0 GCD 笔记

    iOS 下的多线程编程技术从底层往上分别是 NSThread、NSOperation、Grand Central ...

网友评论

    本文标题:Swift3.0 DispatchQueue-对GCD的改写

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