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

Posted

技术标签:

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

【问题讨论】:

类似问题***.com/questions/4344884/… 【参考方案1】:

OperationQueue 在内部使用 Grand Central Dispatch 和 ios

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

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

【讨论】:

NSOperationQueue on iOS 4.0 and later is based on GCD. 为了清楚起见,GCD 使用 DispatchQueue,NSOperationQueue 现在更名为 OperationQueue【参考方案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://***.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")

【讨论】:

以上是关于iOS 应用程序的操作队列与调度队列的主要内容,如果未能解决你的问题,请参考以下文章

ios多线程操作—— GCD串行队列与并发队列

linux内核阻塞IO

Laravel的队列和任务调度的区别

第九天 线程 进程 协程 队列

优先队列底层实现是堆(heap)(操作系统进程调度)

ios/swift 调度队列 - 全局和主队列概念