Ios NSOperationQueue、并发操作和线程
我正在开发一种快速图像扫描应用程序。Ios NSOperationQueue、并发操作和线程,ios,multithreading,grand-central-dispatch,nsoperation,nsoperationqueue,Ios,Multithreading,Grand Central Dispatch,Nsoperation,Nsoperationqueue,我正在开发一种快速图像扫描应用程序。 在-captureOutput:didOutputSampleBuffer:fromConnection:方法中,我提取CVPixelBuffer并将它们添加到NSOperation子类中。NSOperation获取缓冲区并将其转换为保存在文件系统上的映像。 NSOperation的-isConcurrent方法返回YES。创建操作后,将添加到NSOperationQueue 除了一个影响扫描帧速率的问题外,一切正常。 使用时间分析器,我发现一些NSO操作在
在
-captureOutput:didOutputSampleBuffer:fromConnection:
方法中,我提取CVPixelBuffer并将它们添加到NSOperation
子类中。NSOperation
获取缓冲区并将其转换为保存在文件系统上的映像。NSOperation的-isConcurrent
方法返回YES。创建操作后,将添加到NSOperationQueue
除了一个影响扫描帧速率的问题外,一切正常。
使用时间分析器,我发现一些NSO操作在我创建的AVCaputureVideoOutput委托的同一线程上运行:
dispatch_queue_t queue = dispatch_queue_create("it.CloudInTouchLabs.avsession", DISPATCH_QUEUE_SERIAL);
[dataOutput setSampleBufferDelegate:(id)self queue:queue];
当一个操作在AV会话队列的同一线程上运行时,它会影响帧速率,仅在某些线程上发生,可能是GCD决定在活动线程上进行分配。
我找到的唯一解决该问题的方法,是创建一个单独的线程,并将其传递给单个操作,迫使它们在其上运行。
有没有其他方法可以强制在不同的线程上运行操作?
[编辑]
按照@impcc的建议,我做了一些测试。
结果非常有趣,即使有点不一致。
测试平台是一个iPhone 5,通过一个带有16gb RAM四核i7的MBP以调试模式连接。会话的输出速度为60fps,使用RosyWriter apple示例代码中的算法进行测试
针对高优先级队列的AVSession队列同步
- 26 fps,其中有时队列的线程与
行动的细节。委托方法内部花费的时间具有
平均0.02s
- 14 fps,如果主线程
方法,则将强制执行启动
在那个特定的线程上。此线程创建一次并保留
通过虚拟端口激活。。在委托内花费的时间为
0.008。
针对高优先级队列的AVSession队列并发
- 13.5 fps,其中有时队列的线程与操作之一共享。委托方法内部所用的时间已更改
平均0.02s,亚相等于同步对应物
排队
- 14 fps,如果主线程
方法,则将强制执行启动
在那个特定的线程上。此线程创建一次并保留
用虚拟端口活着。在委托内花费的时间为
0.008。
结论
并发队列或串行队列似乎没有太大的区别,但是并发队列对我来说并不合适,因为我需要使用时间戳来保留单个图片的序列。让我吃惊的是,使用一个特别线程的帧下降,即使委托方法内部花费的时间大大减少,帧速率也会下降约10fps。只要相信GCD,帧速率就会更好,但委托方法需要2倍以上的时间才能完成,这可能是因为有时NSD操作也会使用AV队列
我真的不明白为什么在代理内部花费的时间似乎与fps不相关。不是越快越好吗?
通过进一步的调查,似乎在队列中添加并可能执行操作的过程中确实在窃取时间。我认为您可能误解了的含义是并发的。这是完全可以理解的,因为它的名字非常糟糕。当您从-isConcurrent
返回YES
时,它真正的意思是“我将处理与此操作相关的任何并发需求,否则将异步运行。”,NSOperationQueue
可以在添加操作的线程上同步调用操作的-start
。NSOperationQueue
希望您的-start
方法能够启动一个异步进程并立即返回,因为您已经声明将管理自己的并发性。我怀疑这就是你问题的根源
如果您通过覆盖-main
来实现操作,那么您几乎肯定希望从isConcurrent
返回NO
。让事情变得更复杂的是,与isConcurrent
相关的行为在过去几年中已经发生了变化(但所有这些都包含在官方文件中)。可以找到一个关于如何正确执行返回操作的奇妙解释-YES
-from-isConcurrent
NSOperation
我在这里阅读您的问题的方式,听起来不像您的NSOperation
子类实际上需要“管理其自身的并发性”,而是希望它在“后台线程”上异步执行,可能与其他操作“并发”
为了确保AVCaptureVideoDataOutputSampleBufferDelegate
回调的最佳性能,我建议将传递给-setSampleBufferDelegate:queue:
的队列设置为(自身)并发队列,并将其定位于高优先级全局并发队列,如下所示:
dispatch_queue_t queue = dispatch_queue_create("it.CloudInTouchLabs.avsession", DISPATCH_QUEUE_CONCURRENT);
dispatch_set_target_queue(queue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0));
[dataOutput setSampleBufferDelegate:(id)self queue:queue];
然后,您应该使委托回调方法尽可能轻量级——只需打包进行NSOperation
所需的信息,并将其添加到NSOperationQueue
这应确保回调始终优先于NSOperations
。(据我所知,NSOperationQueue
以主队列(对于关联的NSOperationQueue
)为目标