【iOS多线程】GCD基础用法

333 阅读2分钟

GCD, operating at the system level, can better accommodate the needs of all running applications, matching them to the available system resources in a balanced fashion.

文档中介绍,GCD是系统层面上的API,能够协调所有正在运行的APP所使用的资源,在iOS中,Apple是推荐大家使用GCD来进行多线程开发。

DispatchQueue

An object that manages the execution of tasks serially or concurrently on your app's main thread or on a background thread.

DispatchQueue是GCD中的一个类,常用于异步执行任务。

主队列与全局队列用法

// 主队列为串行队列,任务在主线程中执行
let mainQueue = DispatchQueue.main
// 全局队列为并行队列,任务在子线程中执行
let globalQueue = DispatchQueue.global() 

// 主队列添加异步任务,任务在主线程执行
mainQueue.async {
    print(Thread.current) // <NSThread: 0x6000020c0280>{number = 1, name = main}
}
// 全局队列添加异步任务,任务在子线程执行
globalQueue.async {
    print(Thread.current) // <NSThread: 0x600002063a40>{number = 13, name = (null)}
}

串行队列与并行队列用法

 // 自定义串行队列
let serialQueue = DispatchQueue(label: "com.serial")
// 自定义并行队列
let concurrentQueue = DispatchQueue(label: "com.concurrent", attributes: .concurrent) 

for i in 0..<5 {
    // 串行队列异步任务,在子线程中依次执行
    serialQueue.async {
        print(Thread.current) // <NSThread: 0x6000023c9800>{number = 5, name = (null)}
        print(i) // 0 1 2 3 4 5
    }
    
    // 并行队列异步任务,在多个子线程中同时执行
    concurrentQueue.async {
        // 2 0 3 1 4
        print(i)

        // <NSThread: 0x600001007b00>{number = 7, name = (null)}
        // <NSThread: 0x6000010017c0>{number = 6, name = (null)}
        // <NSThread: 0x60000101ccc0>{number = 8, name = (null)}
        // <NSThread: 0x60000100fa00>{number = 3, name = (null)}
        // <NSThread: 0x600001007b00>{number = 7, name = (null)}
        print(Thread.current)
    }
}

同步任务与死锁

// 主队列为串行队列,任务在主线程中执行
let mainQueue = DispatchQueue.main
// 全局队列为并行队列,任务在子线程中执行
let globalQueue = DispatchQueue.global()

globalQueue.async {
    print(Thread.current) // <NSThread: 0x60000100fa00>{number = 3, name = (null)}
    globalQueue.sync {
        // 在当前线程执行同步任务
        print(Thread.current) // <NSThread: 0x60000100fa00>{number = 3, name = (null)}
    }
}

globalQueue.async {
    print(Thread.current) // <NSThread: 0x60000100fa00>{number = 3, name = (null)}
    mainQueue.sync {
        // 主队列的任务除外
        // 主队列的同步/异步任务都在主线程上执行
        print(Thread.current) // <NSThread: 0x600001e1cec0>{number = 1, name = main}
    }
}

// 同步任务容易造成死锁
// 在主线程中往主队列中添加同步任务,造成死锁
mainQueue.sync {
    print(Thread.current) // 死锁,App会崩溃
}

// 在子线程中往执行当前任务的串行队列中添加同步任务,造成死锁
serialQueue.async {
    serialQueue.sync {
        print(Thread.current) // 死锁,App会崩溃
    }
}

DispatchGroup

A group of tasks that you monitor as a single unit.

从文档的描述中,我们可以猜测,DispatchGroup的作用,就是把多个任务统一成一个任务来完成,一起来看看具体的用法。

let group = DispatchGroup()
let queue = DispatchQueue(label: "com.concurrent", qos: .background, attributes: .concurrent)
for i in 0..<5 {
    group.enter()
    queue.async {
        group.leave()
        print(i)
    }
}

// 阻塞当前线程,等待queue中的任务完成
group.wait()

// 不阻塞当前线程,当queue中任务完成时,接收通知
group.notify(qos: .default, flags: [], queue: queue) {
    // do something
}

接下来

我们常常在子线程执行耗时操作,然后切换到主线程来更新UI,

DispatchQueue.global().async {
    // do something time-consuming
    DispatchQueue.main.async {
        // update UI
    }
}

我很好奇这个queue究竟是什么?子线程、主线程是从哪里来的?GCD中的主队列、全局队列,队列的并行、串行,任务的同步、异步究竟是如何实现的? 在下一篇文章中,我们先来看看队列是如何创建的。

【iOS多线程】DispatchQueue原理解析之队列创建