仅具有屏障任务的并发队列

时间:2018-03-30 14:34:33

标签: ios swift multithreading grand-central-dispatch kingfisher

最近,我正在阅读热门图片缓存库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()
        }
    }
}

每个屏障操作都会相互阻塞,使队列实际上成为一个序列。那么,为什么翠鸟使用concurrent队列而不是serial队列?

1 个答案:

答案 0 :(得分:1)

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

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

我不能说明Kingfisher使用concurrent队列背后的具体原因,但只是想注意一个例子用例,当你可能更喜欢concurrent而不是serial时GCD队列安全。使用concurrent可以提供额外的灵活性,因为您可以决定是应该同时执行操作还是使用.barrier标志“连续”执行操作,具体取决于行为。

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