只有屏障任务的并发队列
Concurrent queue with barrier task only
最近在看流行的图片缓存库的代码Kingfisher。
我对 ImageDownloader
上的 GCD 用法感到困惑。在该下载器中,所有与 ImageFetchLoad
(获取图像的任务)相关的操作都被分派到名为 barrierQueue
:
的并发队列
barrierQueue = DispatchQueue(label: "com.onevcat.Kingfisher.ImageDownloader.Barrier.\(name)", attributes: .concurrent)
令人困惑的部分是所有操作都是使用屏障同步调度的:
barrierQueue.sync(flags: .barrier) {
if let URL = task.internalTask.originalRequest?.url, let imageFetchLoad = self.fetchLoads[URL] {
imageFetchLoad.downloadTaskCount -= 1
if imageFetchLoad.downloadTaskCount == 0 {
task.internalTask.cancel()
}
}
}
每个屏障操作都会相互阻塞,这使得队列实际上是一个串行队列。因此,为什么 Kingfisher 使用 concurrent
队列而不是 serial
队列?
在某些情况下,为了 GCD 线程安全,使用 concurrent
队列而不是 serial
队列可能是有意义的。 class 中的所有操作可能不需要或不需要串行执行。例如,对于不修改状态的 "read" 操作,它们 并发 和同步执行是有意义的。即,如果 "read" 操作 returns 信息不依赖于可能被您正在等待的其他操作修改的状态,则没有理由等待串行执行。
因此,在这些情况下,您可以像 Kingfisher 那样使用 concurrent
队列,并为任何改变数据状态的操作设置一个 .barrier
标志,以告诉块等待直到所有其他操作在执行前队列已完成。
我无法说明 Kingfisher 使用 concurrent
队列背后的具体理由,但只是想说明一个示例用例,说明何时您可能更喜欢 concurrent
而不是 serial
用于 GCD 队列安全。使用 concurrent
可以提供额外的灵活性,因为您可以根据行为决定是否应同时执行操作或使用 .barrier 标志 "serially" 。
有关此模式的描述,请查看此处的 .barrier
描述:http://khanlou.com/2016/04/the-GCD-handbook/
最近在看流行的图片缓存库的代码Kingfisher。
我对 ImageDownloader
上的 GCD 用法感到困惑。在该下载器中,所有与 ImageFetchLoad
(获取图像的任务)相关的操作都被分派到名为 barrierQueue
:
barrierQueue = DispatchQueue(label: "com.onevcat.Kingfisher.ImageDownloader.Barrier.\(name)", attributes: .concurrent)
令人困惑的部分是所有操作都是使用屏障同步调度的:
barrierQueue.sync(flags: .barrier) {
if let URL = task.internalTask.originalRequest?.url, let imageFetchLoad = self.fetchLoads[URL] {
imageFetchLoad.downloadTaskCount -= 1
if imageFetchLoad.downloadTaskCount == 0 {
task.internalTask.cancel()
}
}
}
每个屏障操作都会相互阻塞,这使得队列实际上是一个串行队列。因此,为什么 Kingfisher 使用 concurrent
队列而不是 serial
队列?
在某些情况下,为了 GCD 线程安全,使用 concurrent
队列而不是 serial
队列可能是有意义的。 class 中的所有操作可能不需要或不需要串行执行。例如,对于不修改状态的 "read" 操作,它们 并发 和同步执行是有意义的。即,如果 "read" 操作 returns 信息不依赖于可能被您正在等待的其他操作修改的状态,则没有理由等待串行执行。
因此,在这些情况下,您可以像 Kingfisher 那样使用 concurrent
队列,并为任何改变数据状态的操作设置一个 .barrier
标志,以告诉块等待直到所有其他操作在执行前队列已完成。
我无法说明 Kingfisher 使用 concurrent
队列背后的具体理由,但只是想说明一个示例用例,说明何时您可能更喜欢 concurrent
而不是 serial
用于 GCD 队列安全。使用 concurrent
可以提供额外的灵活性,因为您可以根据行为决定是否应同时执行操作或使用 .barrier 标志 "serially" 。
有关此模式的描述,请查看此处的 .barrier
描述:http://khanlou.com/2016/04/the-GCD-handbook/