GCD设置线程之间的调度/优先级

时间:2016-07-28 20:42:09

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

我正在开发一款应用程序,可以从相机中捕获帧并混合在另一个线程更新的图像上。我的问题是每500ms调用一次的图像创建线程会消耗影响另一个线程的峰值计算能力。

这里有一些日志用于澄清:

navigator.navigateTo("search/searchterm") 
// `search` is your view name, `searchterm` is the passed param

正如您所见,captureOutput的帧速率超过30 fps。一旦motionCallback创建图像,帧速率就会下降,然后再次上升。请注意,motionCallback()仅在每15个捕获帧中调用一次,因此平均计算能力应该足够了。

captureOutput()正在如下所示的队列上运行:

captureOutput(): used time:  0.027741014957428  , frame rate:  36.0477077545513
captureOutput(): used time:  0.0285720229148865  , frame rate:  34.9992719444091
captureOutput(): used time:  0.0310209989547729  , frame rate:  32.2362281581567
captureOutput(): used time:  0.0268059968948364  , frame rate:  37.3050852733863
captureOutput(): used time:  0.0263729691505432  , frame rate:  37.9176115624965
motionCallback(): starting drawing: 
captureOutput(): used time:  0.0376390218734741  , frame rate:  26.5681718127947
motionCallback(): elapesed time:  0.0835540294647217
captureOutput(): used time:  0.0581380128860474  , frame rate:  17.2004502795793
captureOutput(): used time:  0.0364410281181335  , frame rate:  27.4415967836645
captureOutput(): used time:  0.0278580188751221  , frame rate:  35.8963070734734
captureOutput(): used time:  0.0283130407333374  , frame rate:  35.3194137435949
captureOutput(): used time:  0.0271909832954407  , frame rate:  36.7768972947616
captureOutput(): used time:  0.0268760323524475  , frame rate:  37.2078730552999

后来我按照以下方式设置了AVCapture:

required init?(coder aDecoder: NSCoder) {
  super.init(coder: aDecoder)
  self.m_captureSessionQueue = DispatchQueue(label: "CaptureSessionOutputQueue", attributes: DispatchQueueAttributes.serial)
}

motionCallback()设置如下:

videoDataOutput.setSampleBufferDelegate(self, queue: self.m_captureSessionQueue)

以后:

let interval = 0.4
if m_manager.isDeviceMotionAvailable {
  m_manager.showsDeviceMovementDisplay = true
  m_manager.deviceMotionUpdateInterval = interval
  // XArbitraryCorrectedZVertical
  m_manager.startDeviceMotionUpdates(using: CMAttitudeReferenceFrame.xArbitraryCorrectedZVertical , to: OperationQueue.main, withHandler: motionCallback)
  print("viewDidLoad(): CM initialized !")
}
像这样

和generateImage():

func motionCallback(_ motion: CMDeviceMotion?, error: NSError?) -> Void {
  guard let mot = motion else {return}
  print("motionCallback(): starting drawing: ")

  let start = NSDate() // <<<<<<<<<< Start time
  self.m_instrview?.update(attitude: mot.attitude)
  self.m_overlayImage = CIImage(image: self.m_instrview!.generateImage()!)

  let end = NSDate()  // <<<<<<<<<<   end time
  let timeInterval: Double = end.timeIntervalSince(start as Date)
  print("motionCallback(): elapesed time: ", timeInterval)
}

我的想法是每次CoreMotion系统获取更新时都会创建一个新的图像。

我的问题是如何平衡motionCallback()的计算时间,以便它不消耗导致帧速率下降的峰值cpu功率?所以我会接受它运行10倍以上但在此期间只消耗1/10的CPU。

有关如何控制这一点的任何想法?

由于 克里斯

1 个答案:

答案 0 :(得分:1)

创建一个异步队列(使用dispatch_queue_create),其优先级低于帧捕获的优先级。在此优先级较低的队列上运行motionCallback。

您在主队列上运行了motionCapture方法,主队列在主线程上运行其任务。不要那样做。

这一行错了:

m_manager.startDeviceMotionUpdates(
  using: CMAttitudeReferenceFrame.xArbitraryCorrectedZVertical , 
  to: OperationQueue.main, 
  withHandler: motionCallback)

更改为:参数。

您需要创建一个新的串行队列,其优先级低于您创建的CaptureSessionOutputQueue,并将其传递给上面的to:参数。

我刚刚开始学习Swift 3,所以我还没有创建调度队列的新代码的语法。