GCD设置调度/线程之间的优先级
问题描述:
我正在研究一个应用程序,该应用程序捕获来自摄像机的帧,并混合由另一个线程更新的图像。我的问题是,每500ms调用一次的图像创建线程会消耗影响其他线程的峰值计算能力。GCD设置调度/线程之间的优先级
这里是一些日志说明:
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倍,但在此期间只消耗CPU的十分之一。
任何想法如何可以控制?
感谢 克里斯
答
比,做你的帧捕捉了一个较低的优先级创建一个异步队列(使用dispatch_queue_create)。在这个较低优先级队列上运行您的motionCallback。
您的motionCapture方法在主队列上运行,主队列在主线程上运行其任务。不要这样做。
此行是错误的:
m_manager.startDeviceMotionUpdates(
using: CMAttitudeReferenceFrame.xArbitraryCorrectedZVertical ,
to: OperationQueue.main,
withHandler: motionCallback)
更改到:参数。
您需要创建一个新的串行队列,其运行优先级低于您创建的CaptureSessionOutputQueue,并将其传递给上面的to:参数。
我刚开始学习Swift 3,所以我没有创建调度队列的新代码的语法。
您的动作回调位于主队列中,其中包括对“generateImage”的调用,这似乎是CPU密集型的功能。请注意,如果您将其分派到后台队列中,您仍然必须在主队列上执行UI更新。 – Paulw11
是的,这正是我的问题,必须在主线程上调用CPU密集型功能。因此,如果我不能对motionCallBack进行优先级排序,那么优先捕获线程的优先顺序是什么?我怎样才能做到这一点 ? – Chris
为什么说cpu密集函数必须在主线程上调用? generateImage是cpu密集型的,但可以在后台线程上运行。一旦完成,在主线程上分派CIImage的分配。使用低优先级线程处理核心运动事件 – Paulw11