NSOperation vs大中央派遣


465

我正在学习iOS的并发编程。到目前为止,我已经阅读了有关NSOperation/NSOperationQueue和的信息GCD使用NSOperationQueueover 的原因是什么GCD,反之亦然?

听起来既像GCDNSOperationQueue抽象NSThreads了用户的显式创建。但是,这两种方法之间的关系对我而言尚不清楚,因此请您提供任何反馈意见!


10
+1是一个好问题-对结果感到好奇。到目前为止,我刚刚读到GCD可以轻松地在CPU内核之间分发,这使其成为“新热点”。
直到2012年


Answers:


517

GCD是基于C的低级API,可非常简单地使用基于任务的并发模型。NSOperation并且NSOperationQueue是做类似事情的Objective-C类。NSOperation首次引入,但从10.5iOS 2开始NSOperationQueue并且在内部使用实现了朋友GCD

通常,您应该使用适合您需求的最高级别的抽象。这意味着您通常应使用NSOperationQueue而不是GCD,除非您需要执行NSOperationQueue不支持的操作。

请注意,NSOperationQueue它不是GCD的“简化版本”;实际上,您可以做很多事情,NSOperationQueue而pure却需要很多工作GCD。(例如:带宽受限的队列一次只运行N个操作;建立操作之间的依赖关系。使用两者非常简单,使用。都NSOperation非常困难GCD。)Apple完成了利用GCD使用来创建非常好的对象友好的API的艰苦工作NSOperation。充分利用他们的工作,除非您有理由不这样做。

警告:另一方面,如果您真的只需要发送一个块,并且不需要提供的任何其他功能NSOperationQueue,那么使用GCD并没有错。只要确保它是完成这项工作的正确工具即可。


1
NSOperation是特定的抽象类。
Roshan 2014年

3
@Sandy实际上相反,NSOperation使用了GCD(至少在更高版本的iOS和OS X中)。
garrettmoon 2014年

1
@BJ Homer我们可以在串行分派队列中添加任务以实现正常。因此Justfy行动队列在这方面的优势
Raj Aggrawal

3
@RajAggrawal是的,那行得通……但是您陷入了串行队列。NSOperation可以执行“在其他三个操作完成后执行此操作,但同时执行所有其他操作”。操作依赖关系甚至可以存在于不同队列上的操作之间。大多数人不需要它,但是如果您这样做,NSOperation将是一个更好的选择。
BJ荷马

369

我对一个相关问题的回答一致,我将不同意BJ的建议,建议您首先通过NSOperation / NSOperationQueue查看GCD,除非后者提供了您所需的GCD不需要的东西。

在使用GCD之前,我在应用程序中使用了很多NSOperations / NSOperationQueue来管理并发。但是,自从我开始定期使用GCD以来,几乎将NSOperations和NSOperationQueues完全替换为块和调度队列。这源于我在实践中使用这两种技术的方式以及我对它们进行的性能分析。

首先,使用NSOperations和NSOperationQueues会产生不小的开销。这些是可可对象,需要对其进行分配和释放。在我编写的一个iOS应用程序中,该应用程序以60 FPS渲染3-D场景,我使用NSOperations封装了每个渲染帧。当我对此进行概要分析时,这些NSOperation的创建和拆除占了正在运行的应用程序中CPU周期的很大一部分,并且正在减慢速度。我用简单的块和GCD串行队列替换了这些,然后开销消失了,从而显着提高了渲染性能。这不是我唯一注意到使用NSOperations产生开销的地方,而且我在Mac和iOS上都看到了这一点。

其次,基于块的调度代码具有优雅之处,使用NSOperations时很难匹配。将几行代码包装在一个块中并将其分派以在串行或并发队列上执行非常方便,其中创建自定义NSOperation或NSInvocationOperation来执行此操作需要更多支持代码。我知道您可以使用NSBlockOperation,但您最好将其分发到GCD。我认为,将这些代码包装在与应用程序中的相关处理内联的块中,比使用单独的方法或自定义的NSOperation封装这些任务可以更好地组织代码。

NSOperations和NSOperationQueue仍然有很好的用途。GCD没有真正的依赖关系概念,其中NSOperationQueues可以建立非常复杂的依赖关系图。在少数情况下,我会使用NSOperationQueues。

总的来说,虽然我通常主张使用最高级别的抽象来完成任务,但是在这种情况下,我主张使用GCD的较低级别的API。在我讨论过的iOS和Mac开发人员中,绝大多数选择使用NSOperations上的GCD,除非他们的目标是不支持它的OS版本(iOS 4.0和Snow Leopard之前的版本)。


20
我只是略微不同意;我经常使用普通的GCD。但是我认为您在此答案中对NSBlockOperation的折扣过高。NSOperationQueue的所有好处(依赖性,可调试性等)也适用于块操作。
BJ Homer

4
@BJHomer-我认为避免NSBlockOperation在我的情况下更多是个人喜好问题,尽管在看到使用NSOperations的开销拖累了几个应用程序后,我总体上回避了。如果我要使用块,那么我倾向于全力以赴GCD,只有在需要依赖支持时才例外。
布拉德·拉尔森

1
+1,感谢您的分析。苹果公司似乎都在倡导两者(就像WWDC 2012在并发UI上的会话一样),因此对此表示赞赏。
orip 2012年

1
@VolureDarkAngel-GCD在处理这样的调度方面非常快。在您描述的情况下,这不应该成为您的瓶颈,除非您由于I / O访问速度慢或某种原因而将某种更新备份到队列中。但是,这里可能不是这样。
布拉德·拉尔森

1
@ asma22-通常可以分块进行计算,但是一个阶段的最终计算可能需要先前几个阶段的结果。在这种情况下,您可以使以后的操作取决于先前的操作,并且将对调度进行管理,以使所有操作在最后一个操作之前完成。
布拉德·拉尔森

101

GCD是基于C的底层API。
NSOperation并且NSOperationQueue是Objective-C类。
NSOperationQueue是目标C包装器GCD。如果使用的是NSOperation,则隐式使用的是Grand Central Dispatch。

GCD优于NSOperation的优势:
i。实施
对于GCD实施非常轻量级
NSOperationQueue是复杂而繁重的

NSOperation相对于GCD的优势:

一世。控制操作时,
您可以暂停,取消,恢复NSOperation

ii。依赖关系
可以建立两者之间的相关性NSOperations
操作将无法启动,直到所有的依赖的成品返回true。

iii。操作
状态可以监视操作或操作队列的状态。准备,执行或完成

iv。最大操作数,
您可以指定可以同时运行的排队操作的最大数目

什么时候去GCD或者NSOperation
何时您想要更多地控制队列使用(上面提到的所有NSOperation 情况)以及在简单的情况下需要较少的开销(您只想在后台进行一些工作而几乎没有额外的工作)使用GCD

参考:
https : //cocoacasts.com/choosing-between-nsoperation-and-grand-central-dispatch/ http://iosinfopot.blogspot.in/2015/08/nsthread-vs-gcd-vs-nsoperationqueue.html http ://nshipster.com/nsoperation/


如上所述,可以在NSOperationQueue中指定最大操作数,那么GCD中的最大操作数(调度队列)是多少?假设我有一个项目,那么我可以做多少个操作(调度队列)。或它们是我们可以做的任何最大限​​制。
Roshan Sah

这取决于系统条件,这里是详细信息:stackoverflow.com/questions/14995801/...
SANGRAM Shivankar

我们也可以使用DispatchWorkItem取消GCD中的任务,也可以暂停和继续执行
Ankit garg

@Ankitgarg如果尚未运行任务,则在DispatchWorkItem上调用cancel将停止执行任务,但不会停止已在执行的任务。以及如何暂停/恢复DispatchWorkItem?
abhimuralidharan

34

NSOperation优于GCD的另一个原因是NSOperation的取消机制。例如,一个500px的应用程序显示了数十张照片,使用NSOperation可以在滚动表视图或集合视图时取消不可见图像单元的请求,这可以大大提高应用程序性能并减少内存占用。GCD无法轻松地支持这一点。

同样,通过NSOperation,可以实现KVO。

是Eschaton的一篇文章,值得阅读。


4
值得注意的是,如果你要取消是加载图像的网络操作,那么你不需要做NSOperation这个,因为 NSURLSessionTask.cancelNSURLSession.invalidateAndCancel提供此功能。通常,NSURLSession提供了的某些功能NSOperationQueue,以及NSURLSessionTask提供了NSOperation
–algal的

@algal如此处的说明(stackoverflow.com/questions/21918722/…),似乎NSURLSession使用NSOperationQueue作为构建块。
kalan nawarathne '16

33

GCD确实比NSOperationQueue低,它的主要优点是它的实现非常轻巧,并且专注于无锁算法和性能。

NSOperationQueue确实提供了GCD中不可用的功能,但是它们付出了不小的代价,NSOperationQueue的实现既复杂又笨重,涉及很多锁定,并且仅以非常小的方式在内部使用GCD。

如果您一定要使用NSOperationQueue提供的功能,但是如果GCD足以满足您的需求,我建议您直接使用它以获得更好的性能,显着降低CPU和电源成本以及更大的灵活性。


24

NSQueueOperations和GCD都可以通过释放UI应用程序主线程来在单独的线程中在后台执行繁重的计算任务。

好吧,根据之前的文章,我们看到NSOperations具有addDependency,因此您可以按顺序将操作逐个排队。

但我也了解了有关GCD串行队列的信息,您可以使用dispatch_queue_create在队列中创建运行操作。这将允许以顺序的方式一个接一个地运行一组操作。

NSQueueOperation相对于GCD的优势:

  1. 它允许添加依赖关系,并允许您删除依赖关系,因此对于一个事务,您可以使用依赖关系顺序运行,而对于其他事务,可以同时运行,而GCD不允许以这种方式运行。

  2. 如果操作在队列中,则很容易取消,如果正在运行,则可以将其停止。

  3. 您可以定义最大并发操作数。

  4. 您可以暂停他们在队列中的操作

  5. 您可以找到队列中有多少未决操作。


6

GCD非常易于使用-如果您想在后台执行某项操作,您所需要做的就是编写代码并将其分派到后台队列中。使用NSOperation做同样的事情是很多额外的工作。

NSOperation的优点是(a)您有一个可以向其发送消息的真实对象,并且(b)您可以取消NSOperation。那不是小事。您需要子类化NSOperation,必须正确编写代码,以便取消和正确完成任务都可以正常工作。因此,对于简单的事情,您可以使用GCD,对于更复杂的事情,您可以创建NSOperation的子类。(有子类NSInvocationOperation和NSBlockOperation,但是它们所做的一切都可以通过GCD轻松完成,因此没有充分的理由使用它们)。


3

好吧,NSOperations只是建立在Grand Central Dispatch之上的API。因此,当您使用NSOperations时,您实际上仍在使用Grand Central Dispatch。NSOperations只是为您提供了一些您可能想要的精美功能。您可以使某些操作依赖于其他操作,在对项目加总后对队列进行重新排序,以及类似的事情。实际上,ImageGrabber已经在使用NSOperations和操作队列!ASIHTTPRequest在后台使用它们,并且您可以根据需要配置用于不同行为的操作队列。那么您应该使用哪个呢?无论哪种对您的应用程序有意义。对于此应用程序,它非常简单,因此我们直接使用了Grand Central Dispatch,无需使用NSOperation的精美功能。但是,如果您的应用需要它们,请随时使用!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.