iOS应用程序的操作队列与调度队列

Lop*_*per 53 iphone cocoa-touch objective-c grand-central-dispatch ios

  1. Operation Queue和Dispatch Queue有什么区别?
  2. 在什么情况下使用它们更合适?

omz*_*omz 58

NSOperationQueue早于Grand Central Dispatch,在iOS上它不使用GCD执行操作(这在Mac OS X上有所不同).它使用常规后台线程,其开销比GCD调度队列多一点.

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

总结一下,NSOperationQueue可能更适合可能需要取消或具有复杂依赖关系的长时间运行操作.对于应该具有最低性能和内存开销的短任务,GCD调度队列更好.

编辑:似乎文档NSOperationQueue已过时,它确实在iOS 4.0及更高版本上使用GCD.

  • [iOS 4.0及更高版本上的NSOperationQueue基于GCD.](https://devforums.apple.com/message/352780#352780) (11认同)
  • 为了清楚起见,GCD使用DispatchQueue,现在将NSOperationQueue重命名为OperationQueue (2认同)

Nit*_*rad 21

  • 首选GCD,其中任务不复杂,并且需要最佳的CPU性能.
  • 首选NSOperationQueue,其中任务很复杂,需要取消或暂停块和依赖关系管理.

GCD是一种表示将同时执行的工作单元的轻量级方法.你没有安排这些工作单位; 系统负责为您安排日程安排.在块之间添加依赖性可能是令人头疼的问 取消或暂停块会为开发人员创建额外的工作!

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

NSOperation和NSOperationQueue是在GDC本身之上制作的更高杠杆API,以面向对象的方式实现并发.

有关详细说明,请参阅此问题:/sf/ask/726133201/


kau*_*hal 8

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

正如我在Apple 开发人员文档中读到的DispatchQueue,现在您可以取消执行任务。为此,您必须在通过 OperationQueue 使用 GCD 时使用DispatchWorkItem

——

调度工作项具有取消标志。如果它在运行之前被取消,调度队列将不会执行它并跳过它。如果它在执行期间被取消,则取消属性返回 true。在这种情况下,我们可以中止执行。此外,工作项可以在其任务完成时通知队列。

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

如下例所示,我检查如下代码

if (task?.isCancelled)! {
    break
}
Run Code Online (Sandbox Code Playgroud)

苹果的定义

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

我从SwiftIndia 的 Medium post 中获取了以下示例。有关更多详细信息,请参阅Apple 文档和 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")
Run Code Online (Sandbox Code Playgroud)