Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concurrent queue with barrier task only

Recently I'm reading the codes of the popular image caching library Kingfisher.

I'm confusing about the GCD usages on the ImageDownloader. In that downloader, all the ImageFetchLoad (task to fetch image) related operations are dispatched to a concurrent queue called barrierQueue:

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

The confusing part is ALL the operations are dispatched using barrier sync:

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

Every barrier operation will block each other which make the queue actually a serial one. Thus, why the Kingfisher use the concurrent queue instead of a serial one?

like image 746
kukushi Avatar asked Apr 27 '26 00:04

kukushi


1 Answers

There are some cases where it may make sense to use a concurrent queue over a serial queue for GCD thread safety. Serial execution may not be desirable or necessary for all operations in a class. For example for "read" operations that do not modify state, it makes sense for them to perform concurrently and synchronously. i.e., if the "read" operation returns information that is not dependent on state that might be modified by other operations you're waiting on, there's no reason to wait for serial execution.

So in these cases you might use a concurrent queue as Kingfisher does, and set a .barrier flag for any operations that mutate data state to tell the block to wait until all other operations in the queue are complete before executing.

I can't speak to the specific rationale behind Kingfisher's use of a concurrent queue, but just wanted to note an example use case of when you might prefer concurrent over serial for GCD queue safety. Using concurrent can provide additional flexibility since you can decide if operations should be executed concurrently or "serially" with a .barrier flag, depending on behavior.

For a description of this pattern, take a look at the .barrier description in here: http://khanlou.com/2016/04/the-GCD-handbook/

like image 171
miweinst Avatar answered Apr 29 '26 13:04

miweinst



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!