【问题标题】:Operation Queue vs Dispatch Queue for iOS ApplicationiOS 应用程序的操作队列与调度队列
【发布时间】:2011-10-28 01:32:44
【问题描述】:
  1. 操作队列和调度队列有什么区别?
  2. 分别在什么情况下使用更合适?

【问题讨论】:

标签: iphone objective-c ios cocoa-touch grand-central-dispatch


【解决方案1】:

OperationQueue 在内部使用 Grand Central Dispatch 和 iOS。

OperationQueue 让您可以更好地控制操作的执行方式。例如,您可以定义各个操作之间的依赖关系,这对于普通的 GCD 队列是不可能的。也可以取消在OperationQueue 中排队的操作(只要操作支持它)。当你在 GCD 调度队列中加入一个块时,它肯定会在某个时候被执行。

综上所述,OperationQueue 可以更适合可能需要取消或具有复杂依赖关系的长时间运行的操作。 GCD 调度队列更适合应该具有最低性能和内存开销的短任务。

【讨论】:

【解决方案2】:
  • 首选 GCD,其中任务不太复杂且需要最佳 CPU 性能
  • 在任务复杂且需要取消或暂停块和依赖管理的情况下,首选 NSOperationQueue。

GCD 是一种轻量级的方式来表示将要同时执行的工作单元。您不安排这些工作单元;系统会为您安排日程。在块之间添加依赖关系可能会让人头疼。作为开发人员,取消或暂停区块会为您带来额外的工作!

与 GCD 相比,NSOperation 和 NSOperationQueue 增加了一点额外的开销,但是您可以在各种操作之间添加依赖关系。您可以重复使用操作、取消或暂停它们。 NSOperation 兼容 Key-Value Observation (KVO);例如,您可以通过监听 NSNotificationCenter 来启动 NSOperation。

NSOperation 和 NSOperationQueue 是更高级别的 API,建立在 GDC 本身之上,以面向对象的方式实现并发。

For detailed explanation, refer this question: https://stackoverflow.com/questions/10373331/nsoperation-vs-grand-central-dispatch

【讨论】:

    【解决方案3】:

    关于 GCD 的一个常见误解是 “一旦您安排了一项无法取消的任务,您就需要为此使用 Operation API”。在 iOS 8 和 macOS 10.10 中引入了 DispatchWorkItem,它在易于使用的 API 中提供了这一确切功能。

    正如我在 Apple 开发人员文档 中阅读的关于 DispatchQueue 的内容,现在您可以取消执行任务。为此,您必须在使用 GCD 而不是 OperationQueue 时使用 DispatchWorkItem

    -

    调度工作项有一个取消标志。如果之前取消 运行时,调度队列不会执行它,会跳过它。如果它 在执行过程中被取消,cancel 属性返回 true。在 这种情况下,我们可以中止执行。工作项也可以通知 任务完成后排队。

    注意: GCD 不执行抢先取消。要停止已经开始的工作项,您必须自己测试是否取消。

    在下面的例子中,我检查了下面的代码

    if (task?.isCancelled)! {
        break
    }
    

    Apple 定义

    DispatchWorkItem 封装了要在调度上执行的工作 队列或调度组内。您还可以将工作项用作 DispatchSource 事件、注册或取消处理程序。

    我从 SwiftIndia's Medium post 中获取了以下示例。更多详情请关注Apple documentation 和 SwiftIndia 的 Medium Post。

    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")
    

    【讨论】:

      猜你喜欢
      • 2017-10-18
      • 2023-03-18
      • 2023-03-06
      • 1970-01-01
      • 1970-01-01
      • 2021-11-02
      • 2017-10-26
      • 1970-01-01
      相关资源
      最近更新 更多