33.多线程之GCD

GCD

GCD即Grand Central Dispatch, 是苹果推荐使用的多线程技术, 它可以充分利用多核.它通过队列来安排任务, GCD队列分为三种:

  • 全局队列
  • 主队列
  • 串行队列

下面我们学习它们

1. 全局队列

全局队列是一个并发队列. 我们来创建一个全局队列:

let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

第一个参数:DISPATCH_QUEUE_PRIORITY_HIGH,DISPATCH_QUEUE_PRIORITY_DEFAULT,DISPATCH_QUEUE_PRIORITY_LOW,DISPATCH_QUEUE_PRIORITY_BACKGROUND中的一个,它指定优先级, 一般用DISPATCH_QUEUE_PRIORITY_DEFAULT即可
第二个参数: 苹果留着的以后扩展用的, 传0即可, 传其它值可能会返回空

2. 串行队列

串行就是一个接一个的执行,只会开一个线程.串行队列要自己创建:

let queue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL)
第一个参数: 队列名字, 随意取
第二个参数: 队列类型, 可以是DISPATCH_QUEUE_SERIAL(串行队列),DISPATCH_QUEUE_CONCURRENT(并行队列)

3. 主队列

它是一个特殊的串行队列, 它的任务都在主线程中运行,程序运行,主线程就已经运行,而主队列也就已经存在, 我可以直接获取:

let queue = dispatch_get_main_queue()

4. GCD的任务派遣方式

GCD的任务派遣方式有两种: dispatch_async 和 dispatch_sync

现在我们实现一个例子, 对上面的三种队列,我们分别使用同步和异步的派遣方式,来观察线程的开启情况:

import UIKit

class ViewController: UIViewController {

    var mainQueue: dispatch_queue_t!
    var globalQueue: dispatch_queue_t!
    var serialQueue: dispatch_queue_t!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        // 全局队列
        globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

        // 串行队列
        serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL)

        // 主队列
        mainQueue = dispatch_get_main_queue()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    @IBAction func globalQueueAsyncAction(sender: AnyObject) {
        dispatch_async(globalQueue) { () -> Void in
            print("全局队列_异步派遣: \(NSThread.currentThread())")
        }
    }

    @IBAction func globalQueueSyncAction(sender: AnyObject) {
        dispatch_sync(globalQueue) { () -> Void in
            print("全局队列_同步派遣: \(NSThread.currentThread())")
        }
    }

    @IBAction func serialQueueAsyncAction(sender: AnyObject) {
        dispatch_async(serialQueue) { () -> Void in
            print("串行队列_异步派遣: \(NSThread.currentThread())")
        }
    }

    @IBAction func serialQueueSyncAction(sender: AnyObject) {
        dispatch_sync(serialQueue) { () -> Void in
            print("串行队列_同步派遣: \(NSThread.currentThread())")
        }
    }

    @IBAction func mainQueueAsyncAction(sender: AnyObject) {
        dispatch_async(mainQueue) { () -> Void in
            print("主队列_异步派遣: \(NSThread.currentThread())")
        }
    }

    @IBAction func mainQueueSyncAction(sender: AnyObject) {
        dispatch_sync(mainQueue) { () -> Void in
            print("主队列_同步派遣: \(NSThread.currentThread())")
        }
    }
}

然后我们查看不同的情况的打印的值,每个按钮点上3遍:

全局队列_异步派遣: <NSThread: 0x7f90e0fac470>{number = 2, name = (null)}
全局队列_异步派遣: <NSThread: 0x7f90e0fac470>{number = 2, name = (null)}
全局队列_异步派遣: <NSThread: 0x7f90e0fac470>{number = 2, name = (null)}

我们可以看出: globalQueue和dispatch_async的组合会开启新的线程


全局队列_同步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}
全局队列_同步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}
全局队列_同步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}

我们可以看出: globalQueue和dispatch_sync的组合不会开启新的线程,就在主线程中运行


串行队列_异步派遣: <NSThread: 0x7f90e0fac470>{number = 3, name = (null)}
串行队列_异步派遣: <NSThread: 0x7f90e0fac470>{number = 3, name = (null)}
串行队列_异步派遣: <NSThread: 0x7f90e0fac470>{number = 3, name = (null)}

我们可以看出: serialQueue和dispatch_async的组合会开启新的线程


串行队列_同步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}
串行队列_同步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}
串行队列_同步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}

我们可以看出: serialQueue和dispatch_sync的组合不会开启新的线程,就在主线程中运行


主队列_异步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}
主队列_异步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}
主队列_异步派遣: <NSThread: 0x7f90e0e04340>{number = 1, name = main}

我们可以看出: mainQueue和dispatch_async的组合不会开启新的线程,就在主线程中运行


主队列_同步派遣即mainQueue和dispatch_sync的组合, 模拟器直接卡死了.

现在我们可以总结一下了:

                globalQueue    serialQueue    mainQueue
dispatch_async  开新线程运行     开新线程运行     主线程运行

dispatch_sync   主线程运行      主线程运行       模拟器卡死

一般的情况:
执行耗时操作, dispatch_async + globalQueue, 然后耗时操作完成, 更新UI的时候dispatch_async + mainQueue

5. GCD的组操作

当要监听一系列任务都执行完成时,如下载多个音乐完成后,我们要给个提示,这就要使用GCD的组了.

我们在storyboard中拖拽一个按钮,添加监听方法:

@IBAction func groupAction(sender: AnyObject) {
        let group = dispatch_group_create()

        dispatch_group_async(group, globalQueue) { () -> Void in
            print("下载音乐1, \(NSThread.currentThread())")
        }

        dispatch_group_async(group, globalQueue) { () -> Void in
            print("下载音乐2, \(NSThread.currentThread())")
        }

        dispatch_group_async(group, globalQueue) { () -> Void in
            print("下载音乐3, \(NSThread.currentThread())")
        }

        dispatch_group_notify(group, globalQueue) { () -> Void in
            print("下载完成")
        }
    }

运行程序, 点击按钮:


下载音乐2, <NSThread: 0x7f966bf38ee0>{number = 3, name = (null)}
下载音乐1, <NSThread: 0x7f966bc28ae0>{number = 2, name = (null)}
下载音乐3, <NSThread: 0x7f966bd28190>{number = 4, name = (null)}
下载完成

可以发现, 异步任务的顺序是不确定的, 但是使用群组可以在所有任务执行完成后执行一个block.

6. 完整代码

import UIKit

class ViewController: UIViewController {

    var mainQueue: dispatch_queue_t!
    var globalQueue: dispatch_queue_t!
    var serialQueue: dispatch_queue_t!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        // 全局队列
        globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

        // 串行队列
        serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL)

        // 主队列
        mainQueue = dispatch_get_main_queue()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


    @IBAction func globalQueueAsyncAction(sender: AnyObject) {
        // 开启新的线程
        dispatch_async(globalQueue) { () -> Void in
            print("全局队列_异步派遣: \(NSThread.currentThread())")
        }
    }

    @IBAction func globalQueueSyncAction(sender: AnyObject) {
        // 运行在主线程
        dispatch_sync(globalQueue) { () -> Void in
            print("全局队列_同步派遣: \(NSThread.currentThread())")
        }
    }

    @IBAction func serialQueueAsyncAction(sender: AnyObject) {
        dispatch_async(serialQueue) { () -> Void in
            print("串行队列_异步派遣: \(NSThread.currentThread())")
        }
    }

    @IBAction func serialQueueSyncAction(sender: AnyObject) {
        dispatch_sync(serialQueue) { () -> Void in
            print("串行队列_同步派遣: \(NSThread.currentThread())")
        }
    }

    @IBAction func mainQueueAsyncAction(sender: AnyObject) {
        dispatch_async(mainQueue) { () -> Void in
            print("主队列_异步派遣: \(NSThread.currentThread())")
        }
    }

    @IBAction func mainQueueSyncAction(sender: AnyObject) {
        dispatch_sync(mainQueue) { () -> Void in
            print("主队列_同步派遣: \(NSThread.currentThread())")
        }
    }

    @IBAction func groupAction(sender: AnyObject) {
        let group = dispatch_group_create()

        dispatch_group_async(group, globalQueue) { () -> Void in
            print("下载音乐1, \(NSThread.currentThread())")
        }

        dispatch_group_async(group, globalQueue) { () -> Void in
            print("下载音乐2, \(NSThread.currentThread())")
        }

        dispatch_group_async(group, globalQueue) { () -> Void in
            print("下载音乐3, \(NSThread.currentThread())")
        }

        dispatch_group_notify(group, globalQueue) { () -> Void in
            print("下载完成")
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值