Home > Enterprise >  iOS concurrent: how to use OperationQueue instead of barrier?
iOS concurrent: how to use OperationQueue instead of barrier?

Time:10-10

When learning OperationQueue, is is possible to use OperationQueue instead of gcd barrier?

Here is the case:

upload 3 images , then upload other 3 images

With barrier, gcd works perfect

    func workFlow(){
        let queue = DispatchQueue(label: "test.concurrent.queue", qos: .background, attributes: .concurrent, autoreleaseFrequency: .workItem)
        queue.async {
            self.uploadImg(idx: "A_0")
        }
        queue.async {
            Thread.sleep(forTimeInterval: 2)
            self.uploadImg(idx: "A_1")
        }
        queue.async {
            self.uploadImg(idx: "A_2")
        }
        queue.async(qos: queue.qos, flags: .barrier) {
            print("group A done")
        }
        print("A: should not be hanged")
        queue.async {
            self.uploadImg(idx: "B_0")
        }
        queue.async {
            self.uploadImg(idx: "B_1")
        }
        queue.async {
            self.uploadImg(idx: "B_2")
        }
        
        queue.async(qos: queue.qos, flags: .barrier) {
            print("group B done")
        }
        print("B: should not be hanged")
    }
    
    
    func uploadImg(idx info: String){
        Thread.sleep(forTimeInterval: 1)
        print("img \(info) uploaded")
    }

While with OperationQueue, there is a little flaw here

The main queue gets hanged, just check the print

"A/B: should not be hanged"

  lazy var uploadQueue: OperationQueue = {
       var queue = OperationQueue()
       queue.name = "upload queue"
       queue.maxConcurrentOperationCount = 5
       return queue
     }()


   func workFlow(){
        let one = BlockOperation {
            self.uploadImg(idx: "A_0")
        }
        let two = BlockOperation {
            Thread.sleep(forTimeInterval: 3)
            self.uploadImg(idx: "A_1")
        }
        let three = BlockOperation {
            self.uploadImg(idx: "A_2")
        }
        uploadQueue.addOperations([one, two, three], waitUntilFinished: true)
        print("A: should not be hanged")

        uploadQueue.addOperation {
            print("group A done")
        }
        let four = BlockOperation {
            self.uploadImg(idx: "B_0")
        }
        let five = BlockOperation {
            self.uploadImg(idx: "B_1")
        }
        let six = BlockOperation {
            self.uploadImg(idx: "B_2")
        }
        uploadQueue.addOperations([four, five, six], waitUntilFinished: true)
        print("B: should not be hanged")
        uploadQueue.addOperation {
            print("group B done")
        }
    }

How to do it better with OperationQueue?

CodePudding user response:

If you do not want the operations added to the queue to block the current thread, waitUntilFinished must be false. But if you set it to true, it will block the current thread until the added operations finish.

Obviously, if you do not wait, it will not block the the main thread, but you will also lose the barrier behavior. But iOS 13 and macOS 10.15 introduced addBarrierBlock. If you really need barriers and must support earlier OS versions, then you will have to use dependencies. But if you were previously using GCD barriers simply to constrain the degree of concurrency, then maxConcurrentOperationCount might render the barrier moot. It all depends upon why you were using barriers with these downloads. (It is a little unusual to see barriers with download queues as it reduces efficiency.)

How to do it better with OperationQueue?"

I assume that uploadImg downloads the image synchronously. I would refactor it to be its own Operation subclass, that does the necessary Operation KVO such as shown here. That wraps download task in operation, but you can do the same with data tasks, too (though the memory impact is much greater).

But it is always advisable to avoid having synchronous network requests to (a) make sure you do not tie up worker threads; and (b) to make the requests cancelable.

  • Related