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

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

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

这里有一些日志来澄清:

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

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

captureOutput() 在这样创建的队列上运行:

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

稍后我像这样设置 AVCapture:

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

motionCallback() 是这样设置的:

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 !")
}

及以后:

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

和 generateImage() 像这样:

func generateImage() -> UIImage {
  UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.main().scale )
  drawHierarchy(in: self.bounds, afterScreenUpdates: true)
  let image = UIGraphicsGetImageFromCurrentImageContext()
  UIGraphicsEndImageContext()
  return image!
}

我的想法是每次 CoreMotion 系统给我更新时我都会生成一个新图像。

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

有什么办法可以控制吗?

谢谢 克里斯

最佳答案

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

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

这一行是错误的:

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

更改为:参数。

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

我才刚刚开始学习 Swift 3,所以我还不知道用于创建调度队列的新代码的语法。

关于ios - GCD设置线程间的调度/优先级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38646353/

相关文章:

ios - 在 didHighlightItemAt 和 didUnhighlightItemAt 上更改 UICollectionViewCell 的背景在滚动时闪烁

xcode - 理解 SpriteKit 节点的概念

ios - 如何在设备上流畅地进行连续的 Action 过程? (GCD)

ios - 为什么 concurrentQueue.sync 不会导致死锁

asynchronous - iPhone - GCD 将异步操作发送到串行调度队列

ios - 无法分配 ViewController 的 Bool 成员

objective-c - Coredata 和 NSOrderedSet - 如何定义集合的顺序?

ios - 方法调用中的额外参数

ios - xcode 4.5, iOS 6.0 SDK 编译错误-base.h

ios - 缩放后图像未在 ScrollView 中居中