串行调度队列上的工作的序列化是在直接提交到队列的工作单元上进行的。一旦执行到达所提交的闭包的末尾(或返回),就可以执行队列上的下一个工作单元。
重要的是,任何其他可能已由闭包启动的异步任务可能仍在运行(或者甚至可能尚未开始运行),但不考虑它们。
例如,对于以下代码:
dispatch_async(serialQueue) {
print("Start")
dispatch_async(backgroundQueue) {
functionThatTakes10Seconds()
print("10 seconds later")
}
print("Done 1st")
}
dispatch_async(serialQueue) {
print("Start")
dispatch_async(backgroundQueue) {
functionThatTakes10Seconds()
print("10 seconds later")
}
print("Done 2nd")
}
输出将类似于:
Start
Done 1st
Start
Done 2nd
10秒后
10秒后
请注意,在调度第二个串行任务之前,第一个 10 秒任务尚未完成。现在,比较一下:
dispatch_async(serialQueue) {
print("Start")
dispatch_sync(backgroundQueue) {
functionThatTakes10Seconds()
print("10 seconds later")
}
print("Done 1st")
}
dispatch_async(serialQueue) {
print("Start")
dispatch_sync(backgroundQueue) {
functionThatTakes10Seconds()
print("10 seconds later")
}
print("Done 2nd")
}
输出将类似于:
Start
10秒后
Done 1st
Start
10秒后
Done 2nd
注意,这次是因为调度了10秒的任务同步地串行队列被阻塞,直到第一个任务完成后第二个任务才开始。
在您的情况下,您所包装的操作很可能会自行调度异步任务(因为这是网络操作的本质),因此串行调度队列本身是不够的。
您可以使用DispatchGroup
阻止您的串行调度队列。
dispatch_async(serialQueue) {
let dg = dispatch_group_create()
dispatch_group_enter(dg)
print("Start")
dispatch_async(backgroundQueue) {
functionThatTakes10Seconds()
print("10 seconds later")
dispatch_group_leave(dg)
}
dispatch_group_wait(dg)
print("Done")
}
这将输出
Start
10秒后
Done
The dg.wait()
阻塞串行队列,直到达到dg.leave
呼叫数量匹配dg.enter
来电。如果您使用此技术,那么您需要小心确保包装的操作调用的所有可能的完成路径dg.leave
。也有一些变化dg.wait()
需要一个超时参数。