ios - 只有屏障任务的并发队列

标签 ios swift multithreading grand-central-dispatch kingfisher

最近在看流行的图片缓存库的代码Kingfisher .

我对 ImageDownloader 上的 GCD 用法感到困惑。在该下载器中,所有与 ImageFetchLoad(获取图像的任务)相关的操作都被分派(dispatch)到一个名为 barrierQueue 的并发队列:

barrierQueue = DispatchQueue(label: "com.onevcat.Kingfisher.ImageDownloader.Barrier.\(name)", attributes: .concurrent)

令人困惑的部分是所有操作都是使用屏障同步分派(dispatch)的:

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()
        }
    }
}

每个屏障操作都会相互阻塞,这使得队列实际上是一个串行队列。因此,为什么翠鸟使用并发队列而不是串行队列?

最佳答案

在某些情况下,为了 GCD 线程安全,使用 concurrent 队列而不是 serial 队列可能是有意义的。对于类中的所有操作,串行执行可能不是理想的或必需的。例如,对于不修改状态的“读取”操作,它们并发 和同步执行是有意义的。即,如果“读取”操作返回的信息不依赖于可能被您正在等待的其他操作修改的状态,则没有理由等待串行执行。

因此在这些情况下,您可以像 Kingfisher 那样使用concurrent 队列,并为任何改变数据状态的操作设置一个 .barrier 标志以告知 block 等待直到队列中的所有其他操作都完成后才执行。

我无法说明 Kingfisher 使用 concurrent 队列背后的具体原理,但只是想说明一个示例用例,说明何时您可能更喜欢 concurrent serial 用于 GCD 队列安全。使用 concurrent 可以提供额外的灵 active ,因为您可以根据行为决定操作是并发执行还是使用 .barrier 标志“串行”执行。

有关此模式的描述,请查看此处的 .barrier 描述:http://khanlou.com/2016/04/the-GCD-handbook/

关于ios - 只有屏障任务的并发队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49576345/

相关文章:

android - 为什么 bindservice 在将其移动到工作线程后仍然会导致应用程序 ANR

ios - 重写 func prepare(for segue : UIStoryboardSegue, sender : Any?) 不能正常工作

swift - 我需要一个可靠的 Swift 3 秒表

c# - .Net 应用程序的默认线程模型

ios - TWTRLogInButton - NSURLErrorDomain 错误 -1012

ios - [NSURL initFileURLWithPath :]: nil string parameter with ARC

ios - 在 Swift 中获取轨道的元数据

iphone - 图标已经包含光泽效果不适用于 ios 5

swift - 创建一个 CountableClosedRange<Character>

c# - 如何在非表单应用程序中生成击键