484

我正在学习 iOS 的并发编程。到目前为止,我已经阅读了NSOperation/NSOperationQueueGCD. 使用over和反之的原因是什么?NSOperationQueueGCD

听起来两者都一样,GCD并且从用户那里NSOperationQueue抽象出显式创建。NSThreads然而,这两种方法之间的关系对我来说并不清楚,所以任何反馈都值得赞赏!

4

9 回答 9

538

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

通常,您应该使用适合您需要的最高抽象级别。这意味着您通常应该使用NSOperationQueue而不是GCD,除非您需要做一些NSOperationQueue不支持的事情。

请注意,这NSOperationQueue不是 GCD 的“简化”版本。事实上,有很多事情你可以NSOperationQueue用 pure 做很多工作GCD。(例如:带宽受限的队列,一次只运行 N 个操作;建立操作之间的依赖关系。两者都非常简单NSOperationGCD使用NSOperation. 除非您有理由不这样做,否则请利用他们的工作。

警告:另一方面,如果您真的只需要发送一个块,并且不需要NSOperationQueue提供的任何附加功能,那么使用 GCD 没有任何问题。只要确保它是适合这项工作的工具。

于 2012-04-29T20:16:49.503 回答
379

根据我对相关问题的回答,我不同意 BJ 并建议您首先查看 GCD 而不是 NSOperation / NSOperationQueue,除非后者提供了 GCD 不需要的东西。

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

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

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

NSOperations 和 NSOperationQueues 仍然有很好的用途。GCD 没有真正的依赖概念,其中 NSOperationQueues 可以设置非常复杂的依赖图。在少数情况下,我为此使用 NSOperationQueues。

总的来说,虽然我通常主张使用完成任务的最高抽象级别,但这是我主张使用 GCD 的较低级别 API 的一个案例。在我与之交谈过的 iOS 和 Mac 开发人员中,绝大多数人选择使用 GCD 而不是 NSOperations,除非他们的目标是不支持它的操作系统版本(iOS 4.0 和 Snow Leopard 之前的那些)。

于 2012-04-30T02:04:20.353 回答
121

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. State of Operation
可以监控一个操作或操作队列的状态。准备、执行或完成

iv. Max Number of Operation
您可以指定可以同时运行的最大排队操作数

什么时候去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/

于 2016-10-15T21:36:14.740 回答
34

NSOperation 优于 GCD 的另一个原因是 NSOperation 的取消机制。例如,一个像 500px 的 App 展示了几十张照片,使用 NSOperation 我们可以在滚动表格视图或集合视图时取消对不可见图像单元格的请求,这可以大大提高 App 性能并减少内存占用。GCD 不能轻易支持这一点。

同样使用 NSOperation,KVO 也成为可能。

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

于 2014-01-02T08:08:16.847 回答
33

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

NSOperationQueue 确实提供了 GCD 中不可用的功能,但它们的成本不菲,NSOperationQueue 的实现复杂且重量级,涉及大量锁定,并且仅以非常最小的方式在内部使用 GCD。

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

于 2012-04-30T00:50:41.983 回答
24

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

好吧,根据之前的帖子,我们看到 NSOperations 具有 addDependency 以便您可以按顺序将您的操作一个接一个地排队。

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

NSQueueOperation 相对于 GCD 的优势:

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

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

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

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

  5. 您可以找到队列中有多少待处理的操作。

于 2014-08-14T20:45:01.603 回答
6

GCD 很容易使用——如果你想在后台做一些事情,你需要做的就是编写代码并将它分派到后台队列中。用 NSOperation 做同样的事情需要做很多额外的工作。

NSOperation 的优点是(a)您有一个可以向其发送消息的真实对象,以及(b)您可以取消 NSOperation。这不是微不足道的。您需要继承 NSOperation,您必须正确编写代码,以便取消和正确完成任务都能正常工作。所以对于简单的事情你使用 GCD,对于更复杂的事情你创建一个 NSOperation 的子类。(有 NSInvocationOperation 和 NSBlockOperation 的子类,但它们所做的一切都使用 GCD 更容易完成,因此没有充分的理由使用它们)。

于 2014-08-06T00:41:19.287 回答
3

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

于 2014-08-13T11:40:15.220 回答
0

我同意@Sangram 和其他答案,但想补充几点。如果我错了,请纠正我。

我认为现在@Sangram 答案的前两点无效(i. Control On Operation ii. Dependencies)。我们也可以通过使用 GCD 来实现这两个。试图通过代码来解释(不要关注代码质量,仅供参考)

func methodsOfGCD() {
    
    let concurrentQueue = DispatchQueue.init(label: "MyQueue", qos: .background, attributes: .concurrent)
    
    
    //We can suspend and resume Like this
    concurrentQueue.suspend()
    concurrentQueue.resume()
    
    //We can cancel using DispatchWorkItem
    let workItem = DispatchWorkItem {
        print("Do something")
    }
    concurrentQueue.async(execute: workItem)
    workItem.cancel()
    
    //Cam add dependency like this.
    //Operation 1
    concurrentQueue.async(flags: .barrier) {
        print("Operation1")
    }

    //Operation 2
    concurrentQueue.async(flags: .barrier) {
        print("Operation2")
    }

    //Operation 3.
    //Operation 3 have dependency on Operation1 and Operation2. Once 1 and 2 will finish will execute Operation 3. Here operation queue work as a serial queue.
    concurrentQueue.async(flags: .barrier) {
        print("Operation3")

    }

}
于 2021-10-03T13:30:50.200 回答