我正在学习iOS的并发编程。到目前为止,我已经了解了NSOperation/NSOperationQueue和GCD。为什么在GCD上使用NSOperationQueue,反之亦然?
听起来好像GCD和NSOperationQueue都从用户那里抽象出了nsthread的显式创建。然而,这两种方法之间的关系对我来说并不清楚,所以任何反馈都很感激!
我正在学习iOS的并发编程。到目前为止,我已经了解了NSOperation/NSOperationQueue和GCD。为什么在GCD上使用NSOperationQueue,反之亦然?
听起来好像GCD和NSOperationQueue都从用户那里抽象出了nsthread的显式创建。然而,这两种方法之间的关系对我来说并不清楚,所以任何反馈都很感激!
当前回答
我同意@Sangram和其他回答,但想补充几点。如果我错了,请指正。
我认为现在@Sangram的答案的前两点是无效的(I .控制操作ii.)。依赖关系)。我们也可以通过使用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")
}
}
其他回答
根据我对一个相关问题的回答,我不同意BJ的观点,建议你先看看GCD而不是NSOperation / NSOperationQueue,除非后者提供了一些GCD不提供的你需要的东西。
在GCD之前,我在我的应用程序中使用了很多NSOperations / NSOperationQueues来管理并发。然而,自从我开始在常规的基础上使用GCD,我几乎完全用块和分派队列替换了NSOperations和NSOperationQueues。这来自于我在实践中使用这两种技术的方式,以及我对它们进行的分析。
First, there is a nontrivial amount of overhead when using NSOperations and NSOperationQueues. These are Cocoa objects, and they need to be allocated and deallocated. In an iOS application that I wrote which renders a 3-D scene at 60 FPS, I was using NSOperations to encapsulate each rendered frame. When I profiled this, the creation and teardown of these NSOperations was accounting for a significant portion of the CPU cycles in the running application, and was slowing things down. I replaced these with simple blocks and a GCD serial queue, and that overhead disappeared, leading to noticeably better rendering performance. This wasn't the only place where I noticed overhead from using NSOperations, and I've seen this on both Mac and iOS.
Second, there's an elegance to block-based dispatch code that is hard to match when using NSOperations. It's so incredibly convenient to wrap a few lines of code in a block and dispatch it to be performed on a serial or concurrent queue, where creating a custom NSOperation or NSInvocationOperation to do this requires a lot more supporting code. I know that you can use an NSBlockOperation, but you might as well be dispatching something to GCD then. Wrapping this code in blocks inline with related processing in your application leads in my opinion to better code organization than having separate methods or custom NSOperations which encapsulate these tasks.
NSOperations和NSOperationQueues仍然有很好的用途。GCD没有真正的依赖关系概念,NSOperationQueues可以建立相当复杂的依赖关系图。我在少数情况下使用NSOperationQueues。
总的来说,虽然我通常主张使用最高级别的抽象来完成任务,但在这种情况下,我主张使用GCD的低级API。在与我交谈过的iOS和Mac开发者中,绝大多数人选择使用GCD而不是NSOperations,除非他们的目标操作系统版本不支持GCD (iOS 4.0和Snow Leopard之前的版本)。
GCD确实比NSOperationQueue级别低,它的主要优势是它的实现非常轻量级,并且专注于无锁算法和性能。
NSOperationQueue确实提供了GCD中无法提供的功能,但它们的成本非常高,NSOperationQueue的实现非常复杂和繁重,涉及大量的锁定,并且在内部只以非常少的方式使用GCD。
如果您需要NSOperationQueue提供的功能,请务必使用它,但如果GCD足以满足您的需求,我建议直接使用它,以获得更好的性能、显著降低CPU和电源成本以及更大的灵活性。
GCD非常容易使用——如果你想在后台做一些事情,你所需要做的就是编写代码并在后台队列上分派它。用NSOperation做同样的事情需要大量额外的工作。
The advantage of NSOperation is that (a) you have a real object that you can send messages to, and (b) that you can cancel an NSOperation. That's not trivial. You need to subclass NSOperation, you have to write your code correctly so that cancellation and correctly finishing a task both work correctly. So for simple things you use GCD, and for more complicated things you create a subclass of NSOperation. (There are subclasses NSInvocationOperation and NSBlockOperation, but everything they do is easier done with GCD, so there is no good reason to use them).
选择NSOperation而不是GCD的另一个原因是NSOperation的取消机制。例如,一个像500px这样显示数十张照片的App,使用NSOperation我们可以在滚动表格视图或集合视图时取消对不可见图像单元格的请求,这可以极大地提高App性能并减少内存占用。GCD不容易支持这一点。
同样使用NSOperation,可以实现KVO。
这里有一篇来自Eschaton的文章值得一读。
我同意@Sangram和其他回答,但想补充几点。如果我错了,请指正。
我认为现在@Sangram的答案的前两点是无效的(I .控制操作ii.)。依赖关系)。我们也可以通过使用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")
}
}