Swift 何时使用GCD队列?何时知道需要它们?敏捷的
在阅读了并发队列和串行队列、同步队列和异步队列之后,我想我已经了解了如何创建队列以及它们的执行顺序。我的问题是,在我看到的任何教程中,没有一个真正告诉您许多用例。例如: 我有一个网络管理器,它使用URLSessions和序列化json向我的api发送请求。将其包装在Swift 何时使用GCD队列?何时知道需要它们?敏捷的,swift,grand-central-dispatch,Swift,Grand Central Dispatch,在阅读了并发队列和串行队列、同步队列和异步队列之后,我想我已经了解了如何创建队列以及它们的执行顺序。我的问题是,在我看到的任何教程中,没有一个真正告诉您许多用例。例如: 我有一个网络管理器,它使用URLSessions和序列化json向我的api发送请求。将其包装在.utility队列或.userInitiated队列中有意义吗?或者我只是不将其包装在队列中 let task = LoginTask(username: username, password: password) let net
.utility
队列或.userInitiated
队列中有意义吗?或者我只是不将其包装在队列中
let task = LoginTask(username: username, password: password)
let networkQueue = DispatchQueue(label: "com.messenger.network",
qos: DispatchQoS.userInitiated)
networkQueue.async {
task.dataTask(in: dispatcher) { (user, httpCode, error) in
self.presenter?.loginUserResponse(user: user, httpCode: httpCode, error: error)
}
}
我的问题是:是否有任何指南可以让我知道何时需要使用队列,因为我在任何地方都找不到这些信息。我意识到苹果提供了示例用法,尽管它非常模糊调度队列在许多用例中使用,因此很难列举它们,但两个非常常见的用例如下:
imageQueue.async {
// manipulate the image here
// when done, update the UI:
DispatchQueue.main.async {
// update the UI and/or model objects on the main thread
}
}
URLSession
为您管理所有这些,因此使用队列来实现这一点没有什么价值
为了充分披露,在上述基本调度队列之上和之外,有许多不同的工具直接使用GCD(例如调度组或调度源)或间接使用GCD(例如操作队列):
- 调度组:有时,您将启动一系列异步任务,并希望在所有任务完成时收到通知。您可以使用调度组(请参见随机示例)。这使您无需跟踪所有这些任务何时由自己完成
- Dispatch“apply”(现在称为
):有时,当您运行一些大规模并行任务时,您希望使用尽可能多的线程。因此,concurrentPerform
可以让您有效地并行执行concurrentPerform
循环,苹果针对您的特定设备的内核和CPU数量进行了优化,同时不会在任何时候让它充斥太多并发任务,耗尽有限数量的工作线程。有关并行运行for
循环的示例,请参见for
- 派遣来源:
- 例如,如果您有一些正在做大量工作的后台任务,并且您希望随着进度更新UI,那么有时候这些UI更新的速度可能比UI处理它们的速度更快。因此,您可以使用分派源(DispatchSourceUserDataAdd)将后台进程与UI更新分离。参见上述示例
- 传统上,计时器在主运行循环上运行。但有时您希望在后台线程上运行它,但使用
计时器执行此操作非常复杂。但您可以使用
(GCD计时器)在主队列以外的队列上运行计时器。有关如何创建和使用调度计时器的示例,请参见。调度计时器还可用于避免一些强引用循环,这些循环很容易通过基于DispatchSourceTimer
目标
的
计时器
对象引入
- 障碍:有时,在使用并发队列时,您希望大多数内容并发运行,但其他内容相对于队列上的其他内容串行运行。屏障是一种表示“将此任务添加到队列中,但确保它不会与该队列上的任何其他任务同时运行”的方式 一个障碍的例子是读写器模式,其中从某个内存资源的读取可以与所有其他读取同时发生,但任何写入都不能与队列上的任何其他内容同时发生。看到或看到
- 分派信号量:有时您需要让两个在不同线程上运行的任务相互通信。您可以使用一个线程的信号量来“等待”另一个线程的“信号”
信号量的一个常见应用是使固有的异步任务以更同步的方式运行
这种方法的优点是,在异步网络请求完成之前,调度的任务不会完成。因此,如果您需要发出一系列网络请求,但不让它们同时运行,那么信号量可以完成这一任务 不过,信号量应该少用,因为它们本身效率很低(通常会阻塞一个线程等待另一个线程)。另外,确保从不等待来自主线程的信号量(因为这样做会破坏异步任务的目的)。这就是为什么在上面的示例中,我等待的是networkQueue.async { let semaphore = DispatchSemaphore(0) let task = session.dataTask(with: url) { data, _, error in // process the response // when done, signal that we're done semaphore.signal() } task.resume() semaphore.wait(timeout: .distantFuture) }
,而不是主队列。所有这些都已经说过了网络队列