大中央调度室教程

283 阅读5分钟

苹果公司在2009年发布的Grand Central Dispatch是为了管理同时运行的任务,对它们进行排队执行,并安排它们在后台未被占用的处理器上执行。

在Apache许可下发布的GCD包含一个开源库,通常被称为GCD或libdispatch。这个库在后台执行繁重的任务操作,保持主线程的顺利运行,并提供更快的响应时间。

GCD将任务作为一个不接受参数的空块或函数来工作。

我们将讨论GCD如何提供多线程和队列,以及探讨GCD用其技术和功能解决了哪些问题。

Grand Central Dispatch中的线程、多线程和队列

为了真正理解GCD,我们将回顾线程、多线程和队列。

线程

GCD中的线程包含主线程和后台线程;所有的任务都在这些线程上执行。尽可能地保持主线程的自由是很重要的,这样我们的用户界面才能保持快速和响应。任何繁重的任务都必须推送到后台线程。

多线程

因为CPU一次执行一个任务,我们可以使用多线程使CPU在不同的任务之间切换,让它同时执行多个任务。

多线程可以提高响应速度,减少执行多个任务时的滞后性,确保主线程不被打断。

队列

队列类似于公交线路。想象一下,人们在一个公共汽车站等待进入一辆公共汽车。队伍中的第一个人代表队列,进入公交车后离开队伍,这在编程中被称为先入先出。

在GCD中,队列是一组等待在一个线程上执行的代码块或函数

有两种类型的队列。

  1. 串行队列,从第一个到最后一个,一次一个地执行任务
  2. 一个并发队列同时执行所有任务;任务根据正在执行的操作完成

就线程而言,并发队列在后台线程上工作,而主线程是串行队列。一个应用程序使用主队列来串行执行任务,并将繁重的任务分派给并发队列。这就是Grand Central Dispatch的作用。

Grand Central Dispatch能解决什么问题?

如果没有在后台线程上执行繁重任务的能力,任务就会以串行方式完成,从而减慢了性能。

但通过创建队列并将代码块放入队列,GCD将长而重的任务带到后台线程中执行。队列中等待执行的代码块被保存在一个闭包中。

GCD技术

GCD使用的技术对执行并发代码提供了全面的支持。

我们将回顾一些对iOS开发者有用的GCD技术,包括。

  • 如何安排和管理任务与DispatchQueue
  • 将任务作为一个单元进行分组和同步,用DispatchGroup

DispatchQueue

这就是GCD通过将任务打包成一个块或函数来创建任务,并按照执行顺序或复杂程度将其放入队列。这可以使我们的任务队列保持有序,并有助于串行或并发地执行它们。

有三种类型的DispatchQueue

  • 主队列是串行的,在主线程上运行,用于UI相关的操作
  • 全局队列是并发队列,按优先级顺序执行任务
  • 自定义队列是自定义的串行和并发队列

创建一个DispatchQueue ,内容如下。

let dispatchQueue = DispatchQueue(label: "myqueue")

然后我们可以通过添加下面的代码使任务同步或异步执行。

let dispatchQueue = DispatchQueue(label: "myqueue")

// Code executes synchronously
dispatchQueue.sync {
    print("Do something synchronous")
}

// Code executes asynchronously
dispatchQueue.async {
    print("Do something asynchronous")
}

如果我们只想同步执行我们的任务,我们添加以下内容。

let dispatchQueue = DispatchQueue(label: "myqueue")

// Task is synchronous
dispatchQueue.sync {
    // Set timeinterval
    Thread.sleep(forTimeInterval: 5)
    print("Do something synchronous")
}

print("Do something")

// Do something synchronous
// Do something

注意,print("Do something") ,必须等待第一个任务完成。在这个例子中,第一个任务延迟5s,执行,然后进入到下一个代码。

如果我们需要我们的任务以异步方式运行,DispatchQueue 仍然可以帮助我们。当异步运行任务时,它们在自己的时间内完成,而主线程仍然同步执行。

let dispatchQueue = DispatchQueue(label: "myqueue")


dispatchQueue.async {
    Thread.sleep(forTimeInterval: 1)
    print("Do something asynchronous")
}

print("Do something")

// Do something
// Do something asynchronous

因为我们为"Do something asynchronous" 运行了dispatchQueue.async ,所以"Do something" 首先返回。

DispatchGroup

DispatchGroup 的主要目的是为了等待数据。当任务完成后,它们会等待整个组的任务完成,然后再转到下一个操作。因此,当我们有一组并发的任务时,当任务完成时,一个DispatchGroup 会通知我们。

当我们创建一个DispatchGroup ,我们可以创建一个自定义的并发和串行队列,其异步任务链接到同一个组。

如果我们想在每个组的任务完成时得到通知,我们可以使用group.notify ,它来自于我们之前声明的DispatchGroup

let group = DispatchGroup()

// Concurrent queue
let queue = DispatchQueue(label: "com.logrocket.concurrentqueue", attributes: .concurrent)

// Link the Queue to Group
queue.async(group: group) {  
    Thread.sleep(forTimeInterval: 3)
    print("My first task")
}

// Serial queue
let queue2 = DispatchQueue(label: "com.logrocket.serialqueue", attributes: .serial)

// Link the Queue to Group
queue2.async(group: group) {  // Group Linked
    print("My second task")
}


// Notify us for completion of tasks on main thread.
group.notify(queue: DispatchQueue.main) {
    Thread.sleep(forTimeInterval: 1)
    print("All Concurrent task done")
}

print("Waiting for tasks")

/* Output:
  My Task
  Concurrent task done
  Waiting for tasks
*/

这与semaphores的工作原理类似,但在我们的案例中,如果我们的任务没有接触到共享资源,我们必须使用DispatchGroup

结论

通过GCD,我们可以将管理线程的责任从主程序转移到操作系统。实现并发执行模式不再是开发人员必须负责的事情了。

The postGrand Central Dispatch tutorial appeared first onLogRocket Blog.