我正在使用具有 QoS 背景的串行队列
let serialQueue = DispatchQueue(label: "queue1", qos: DispatchQoS.background)
分配一个同步作业,两个异步作业:
func serialTask() {
serialQueue.sync {
for i in 0..<10 {
print("🔷", i)
}
}
serialQueue.async {
for i in 20..<30 {
print("⚪️", i)
}
}
serialQueue.async {
for i in 101..<120 {
print("🔷", i)
}
}
}
所有 3 个作业都在一个接一个地执行同步,但最后两个作业是异步的。异步作业是否在串行队列中同步。
最佳答案
让我看看是否可以阐明 async
与 sync
之间的区别。
我将在我的示例中进行一些更改:
我将使用 Instruments 的“兴趣点”来显示任务何时运行,而不是使用
print
语句。 (参见 WWDC 2019 Getting Started With Instruments。)这样我们就可以以图形方式查看行为。我会在 dispatch 某些东西时发布一个简单的“兴趣点”事件路标 (Ⓢ),我会将 dispatch 的任务包裹在“兴趣区域”(一个水平条)中,以图形方式说明某个过程的持续时间。
我会将您的
for
循环更改为Thread.sleep(forTimeInterval: 1)
,模拟一些耗时的过程。如果您只有一个快速的for
循环,事情会发生得如此之快以至于无法辨别线程真正发生了什么。
所以,考虑:
import os.signpost
private let pointsOfInterest = OSLog(subsystem: "GCD Demo", category: .pointsOfInterest)
func tasks(on queue: DispatchQueue) {
pointsOfInterestRange(with: "tasks(on:)") {
os_signpost(.event, log: pointsOfInterest, name: "1") // first Ⓢ
queue.sync { self.oneSecondProcess(with: "1") }
os_signpost(.event, log: pointsOfInterest, name: "2") // second Ⓢ
queue.async { self.oneSecondProcess(with: "2") }
os_signpost(.event, log: pointsOfInterest, name: "3") // third Ⓢ
queue.async { self.oneSecondProcess(with: "3") }
}
}
func oneSecondProcess(with staticString: StaticString) {
pointsOfInterestRange(with: staticString) {
Thread.sleep(forTimeInterval: 1)
}
}
func pointsOfInterestRange(with staticString: StaticString, block: () -> Void) {
let identifier = OSSignpostID(log: pointsOfInterest)
os_signpost(.begin, log: pointsOfInterest, name: staticString, signpostID: identifier)
block()
os_signpost(.end, log: pointsOfInterest, name: staticString, signpostID: identifier)
}
这就像您的示例,但不是 print
语句,而是路标语句,在 Instruments 的“兴趣点”工具中生成以下图形时间线:
所以,你可以看到:
底部的
tasks(on:)
函数发出了sync
调度,第一个 Ⓢ 路标。它等待
sync
任务“1”完成,然后再继续,此时它发出两个后续调度,第二个和第三个 Ⓢ 路标(发生得如此之快它们在图中连续重叠)。但是
tasks(on:)
不会等待两个async
任务“2”和“3”完成。一旦完成分派(dispatch)那些async
任务,它就会立即返回(因此tasks(on:)
范围会立即停止)。由于后台队列是串行的,所以三个派发任务(“1”、“2”、“3”)依次执行,一个接一个。
但是,如果您将其更改为使用并发队列:
let queue = DispatchQueue(label: "...", attributes: .concurrent)
然后您可以看到两个 async
任务现在相互并发运行:
这一次,task(on:)
调度 sync
调用,等待它完成,然后,只有当 sync
调用完成后 seriesOfTasks
可以继续分派(dispatch)两个 async
调用(在这种情况下,不等待那些分派(dispatch)任务完成)。
如您所见,async
和sync
的行为是不同的。对于 sync
,调用线程将等待分派(dispatch)的任务完成,但对于 async
,它不会。
从上面可以得出两个主要结论:
sync
与async
的选择决定了当前线程的行为(即它是否应该等待分派(dispatch)的任务)。而且,作为一般规则,我们通常会避免在执行任何耗时操作时从主线程调用
sync
(因为这最终会阻塞主线程)。串行队列与并发队列的选择决定了您分派(dispatch)的工作的行为,即它可以与该队列上的其他任务同时运行,还是一个接一个地连续运行。
关于swift - 在 GCD 中是通过异步操作 Swift 同步的串行队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49249654/