Frameworks — DispatchQueue

DispatchQueue 是 GCD(Grand Central Dispatch)中最常用的类之一,它提供了一种基于队列(queue)的多任务并发管理方式,允许在并发操作中调度任务。它的主要功能是在主线程或后台线程上执行同步任务或异步任务,使用起来高效又直观。

以下是对 DispatchQueue 的接口结构、功能说明以及使用方法的详细介绍。


1. DispatchQueue 功能概览 #

DispatchQueue 基于先进先出 (FIFO) 队列运行。它负责管理任务的调度并将其分发到相应的线程上。

主要功能: #

  1. 控制任务在主线程后台线程上运行。
  2. 支持同步(sync)和异步(async)任务。
  3. 提供串行队列并发队列,以灵活实现任务调度。
  4. 提供 QoS(Quality of Service,服务质量)设置,用于控制任务优先级。
  5. 借助定时器和 DispatchWorkItem 提供延迟执行、循环执行以及任务取消功能。

2. DispatchQueue 的接口结构 #

DispatchQueue 主要通过以下方法和接口调度任务:

创建队列 #

方法说明
DispatchQueue.main获取主队列,用于在主线程运行任务。
DispatchQueue.global(qos: DispatchQoS)获取全局并发队列,可以指定 QoS 切换任务的优先级。
DispatchQueue(label:)创建自定义队列(串行或并发)。默认是串行队列,可通过配置使其提供并发功能。

任务执行方式 #

方法说明
async {}异步任务,立即返回,不阻塞当前线程。
sync {}同步任务,阻塞当前线程直到任务完成。
asyncAfter(deadline:execute:)延迟调度任务。

其它实用功能 #

方法说明
DispatchWorkItem包装任务,可以控制任务的状态,例如取消任务。
DispatchSourceTimer创建定时器任务。

3. DispatchQueue 的使用说明 #

以下是 DispatchQueue 的一些常见用法和代码示例:


(1) 使用主队列 #

主队列是一种特殊的串行队列,所有的任务会在主线程执行,适用于更新 UI 操作。

DispatchQueue.main.async {
    // 在主线程上运行的任务,通常是刷新 UI
    someView.text = "Hello, DispatchQueue!"
}

(2) 使用全局并发队列 #

使用全局并发队列适合执行耗时任务,例如下载文件或后台数据处理。可以通过 qos 参数指定任务的优先级。

  • 常见的 QoS:
    • .userInteractive:用户交互任务,需立即执行(如 UI 刷新)。
    • .userInitiated:用户发起的任务(优先级高,如文件打开)。
    • .utility:后台长时间运行的任务(如文件下载、数据分析)。
    • .background:低优先级任务(如预加载)。
// 从全局并发队列调度任务(优先级设置为 .userInitiated)
DispatchQueue.global(qos: .userInitiated).async {
    print("正在下载数据")

    // 模拟耗时操作
    Thread.sleep(forTimeInterval: 2)

    DispatchQueue.main.async {
        print("UI 更新完成")
    }
}

(3) 创建自定义队列 #

串行队列(Serial Queue) #

串行队列中的任务按顺序一个接一个执行。

let serialQueue = DispatchQueue(label: "com.example.serialQueue")

serialQueue.async {
    print("任务 1 开始")
    Thread.sleep(forTimeInterval: 1) // 模拟耗时任务
    print("任务 1 完成")
}

serialQueue.async {
    print("任务 2 开始")
    Thread.sleep(forTimeInterval: 1)
    print("任务 2 完成")
}

并发队列(Concurrent Queue) #

并发队列中的任务可以同时执行,提高执行效率:

let concurrentQueue = DispatchQueue(label: "com.example.concurrentQueue", attributes: .concurrent)

concurrentQueue.async {
    print("任务 A 开始")
    Thread.sleep(forTimeInterval: 1)
    print("任务 A 完成")
}

concurrentQueue.async {
    print("任务 B 开始")
    Thread.sleep(forTimeInterval: 2)
    print("任务 B 完成")
}

concurrentQueue.async {
    print("任务 C 开始")
    Thread.sleep(forTimeInterval: 0.5)
    print("任务 C 完成")
}

(4) 延迟执行任务 #

通过 asyncAfter 方法,可以延迟指定时间后执行任务。例如:

let delayQueue = DispatchQueue(label: "com.example.delay")

let delayTime: DispatchTime = .now() + 2 // 延迟 2 秒
delayQueue.asyncAfter(deadline: delayTime) {
    print("延迟 2 秒后执行任务")
}

(5) DispatchWorkItem:控制和取消任务 #

通过 DispatchWorkItem,你可以封装任务并在需要时取消它。

let workItem = DispatchWorkItem {
    print("执行工作任务")
}

// 提交任务
DispatchQueue.global().async(execute: workItem)

// 如果需要取消任务
workItem.cancel()

在任务执行前检查是否已被取消:

let workItem = DispatchWorkItem {
    if workItem.isCancelled {
        print("任务已取消")
        return
    }
    print("执行工作任务")
}
DispatchQueue.global().async(execute: workItem)

(6) 定时器任务 #

创建一个定时任务,使用 DispatchSourceTimer

let timer = DispatchSource.makeTimerSource()

// 配置定时器:延迟 1 秒开始执行,并每隔 2 秒执行一次
timer.schedule(deadline: .now() + 1, repeating: 2)

timer.setEventHandler {
    print("定时器触发任务")
}

// 启动定时器
timer.activate()

// 停止定时器任务
DispatchQueue.global().asyncAfter(deadline: .now() + 10) {
    timer.cancel()
    print("定时器任务结束")
}

(7) 同步任务 (sync) 的使用 #

同步任务会阻塞当前线程,直到任务完成。避免在主线程中使用它以防止死锁。

let serialQueue = DispatchQueue(label: "com.example.serialQueue")

serialQueue.sync {
    print("同步任务 1")
}

serialQueue.sync {
    print("同步任务 2")
}

4. DispatchQueue 的注意事项 #

  1. 避免主线程阻塞

    • 不要在主线程上运行耗时任务(如文件 I/O、网络请求),否则会导致 UI 卡顿。
  2. 死锁问题

    • 如果主线程中调用同步任务(sync),而该任务又等待主线程完成,容易引发死锁:
      DispatchQueue.main.sync {
          print("死锁会发生!")
      }
      
  3. QoS 的使用

    • 为不同任务设置不同的 QoS 以优化系统资源使用。
  4. 任务取消

    • 使用 DispatchWorkItem 可以追踪和取消任务,但实际已启动的任务不能被实际中断。

5. 总结与应用场景 #

使用场景解决方法
主线程更新 UIDispatchQueue.main.async
后台处理任务DispatchQueue.global().async 或自定义队列
任务控制及取消使用 DispatchWorkItem
延迟任务使用 .asyncAfter
循环/定时任务使用 DispatchSourceTimer

DispatchQueue 是高效的任务管理工具,通过它你可以灵活调度任务、优化并发性能。

本文共 2022 字,上次修改于 Jan 2, 2025