1

I'm trying to improve the time it takes for a task to finish by leveraging multithreading/paralleling.
I'm reading CMSampleBuffers from a video track, manipulating them, then storing them back to an array for later use. Because each manipulation is "costly" in terms of RAM and CPU, I'm using DispatchSemaphore to limit the number of parallel tasks (5 in the example).

Basically, I'm trying to make the "system" process more than a single frame in a time, and not above 5 so the device won't crash due to memory issues. In the current implementation below it's for some reason doing it almost serialize and not in parallel.
Any help will be highly appreciated!

I tried taking reference from here: How to limit gcd queue buffer size for the implementation.

Code:

class MyService {

  let semaphore = DispatchSemaphore(value: 5)
  let processQueue = DispatchQueue(label: "custom.process", attributes: .concurrent)

    func startReading() {

        for sampleBuffer in sampleBuffers {
            // signal wait
            semaphore.wait()

            // async queue
            processQueue.async {

                // run taks
                self.process(buffer: sampleBuffer) { pixelBuffer in

                    // singal to semaphore
                    self.semaphore.signal()

                }
            }
        }
    }


  func process(buffer: CMSampleBuffer, completion: @escaping (CVPixelBuffer) -> (Void)) {

        // run on a background thread to avoid UI freeze
        DispatchQueue.global(qos: .userInteractive).async {

            // Do something
            // Do something
            // Do something
            // Do something
            completion(processedBuffer)
        }   
       
    }

}
Roi Mulia
  • 5,626
  • 11
  • 54
  • 105
  • Dispatch to a global queue, even async, just means that the dispatch call will return immediately. If a global queue is blocked, then it won't process any more blocks. Your "process" function isn't dispatching to a background thread. – gnasher729 Nov 22 '22 at 13:47
  • Hey @gnasher729, how are you doing? Should i remove the DispatchQueue.global()? – Roi Mulia Nov 22 '22 at 14:00
  • Yes, you have already dispatched your work onto a concurrent queue. Dispatching it asynchronously again is unnecessary. You should be careful how you call `startReading`; if you call it on the main queue then you will block the main thread. – Paulw11 Nov 22 '22 at 19:15
  • Roi, the `process` method should not be dispatching to the global queue and the `startReading` should. That having been said, you really need to provide a [reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) that illustrates the problem. I'm not even sure what to make of the assertion that it “almost” runs serially rather than in parallel. Also, are any of the “do something” tasks asynchronous, or all they all synchronous tasks? I ask because if they're synchronous tasks that you want to run in parallel, that offords simpler and less convoluted solution. – Rob Nov 24 '22 at 00:55
  • Hey Rob! I'll make a gist and post it here, thanks! – Roi Mulia Nov 24 '22 at 10:21
  • Hey @Rob, seems like the issue is deeper than expected. I opened a new issue with a PoC repository you can examine. Can you take a quick look? Thanks! https://stackoverflow.com/questions/74561058/coreml-cant-work-in-concurrency-multithreading – Roi Mulia Nov 24 '22 at 12:48

0 Answers0