IOS 应用中的操作队列与调度队列

  1. 操作队列和分派队列有什么区别?
  2. 在什么情况下使用它们更合适?
38857 次浏览

OperationQueue内部使用中央车站调度系统和 iOS。

OperationQueue使您可以更好地控制操作的执行方式。例如,您可以定义各个操作之间的依赖关系,而普通的 GCD 队列不可能做到这一点。也可以取消在 OperationQueue中排队的操作(只要操作支持它)。当您在 GCD 分派队列中加入一个块时,它肯定会在某个时刻被执行。

总而言之,OperationQueue更适合于可能需要取消或具有复杂依赖关系的长期运行操作。对于性能和内存开销应该最小的短任务,GCD 调度队列更适合。

  • 喜欢任务不太复杂且需要 最佳 CPU 性能的 GCD。
  • 选择任务复杂且需要 canceling or suspending a block and dependency management的 NSOperationQueue。

GCD 是一种轻量级的方法,用于表示将要并发执行的工作单元。您不需要安排这些工作单元; 系统负责为您安排日程。在块之间添加依赖关系可能是一个令人头疼的问题。取消或暂停一个块为您作为一个开发人员创建额外的工作!

与 GCD 相比,NSOperation 和 NSOperationQueue 增加了一点额外的开销,但是您可以在各种操作之间添加依赖关系。您可以重用操作,取消或挂起它们。NSOperation 与键值观察(KVO)兼容; 例如,可以通过侦听 NSNotificationCenter 来运行 NSOperation。

NSOperation 和 NSOperationQueue 是在 GDC 本身之上制作的高级 API,用于以面向对象的方式实现并发。

如需详细解释,请参阅以下问题: https://stackoverflow.com/questions/10373331/nsoperation-vs-grand-central-dispatch

关于 GCD 的一个常见的误解是 “once you schedule a task it can’t be canceled, you need to use the Operation API for that”。随着 iOS 8和 macOS 10.10的引入,DispatchWorkItem在一个易于使用的 API 中提供了这种确切的功能。

正如我在 Apple developer documentation中读到的 调度队列,现在您可以从执行中取消任务。为此,必须在使用 GCD over OperationQueue 时使用 DispatchWorkItem

-

A dispatch work item has a cancel flag. If it is cancelled before 运行时,分派队列将不会执行它,并将跳过它 执行期间取消,则取消属性返回 true。在 在这种情况下,我们可以中止执行 当他们的任务完成时排队。

注意: GCD 不执行优先取消。要停止已经启动的工作项,必须自己测试是否有取消。

在下面的示例中,我按照下面的代码进行了检查

if (task?.isCancelled)! {
break
}

苹果的定义

DispatchWorkItem 封装要在分派上执行的工作 也可以将工作项用作 DispatchSource 事件、注册或取消处理程序。

我采用了下面的例子从 SwiftIndia’s Medium Post 。更多的细节,请按照 苹果文档和 SwiftIndia 的中期职位。

import Foundation
import PlaygroundSupport


PlaygroundPage.current.needsIndefiniteExecution = true


let concurrentQueue = DispatchQueue(label: "com.queue.Concurrent", attributes: .concurrent)


func performAsyncTaskInConcurrentQueue() {
var task:DispatchWorkItem?
    

task = DispatchWorkItem {
for i in 1...5 {
if Thread.isMainThread {
print("task running in main thread")
} else{
print("task running in other thread")
}
            

if (task?.isCancelled)! {
break
}
            

let imageURL = URL(string: "https://upload.wikimedia.org/wikipedia/commons/0/07/Huge_ball_at_Vilnius_center.jpg")!
let _ = try! Data(contentsOf: imageURL)
print("\(i) finished downloading")
}
task = nil
}
    

/*
There are two ways to execute task on queue. Either by providing task to execute parameter or
within async block call perform() on task. perform() executes task on current queue.
*/
// concurrentQueue.async(execute: task!)
    

concurrentQueue.async {
task?.wait(wallTimeout: .now() + .seconds(2))
// task?.wait(timeout: .now() + .seconds(2))
task?.perform()
}
concurrentQueue.asyncAfter(deadline: .now() + .seconds(2), execute: {
task?.cancel()
})
    

task?.notify(queue: concurrentQueue) {
print("\n############")
print("############")
print("###### Work Item Completed")
}
}


performAsyncTaskInConcurrentQueue()


print("###### Download all images asynchronously and notify on completion ######")
print("############")
print("############\n")