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
)为目标