簡體   English   中英

iOS 應用程序的操作隊列與調度隊列

[英]Operation Queue vs Dispatch Queue for iOS Application

  1. Operation Queue 和 Dispatch Queue 有什么區別?
  2. 在什么情況下分別使用更合適?

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

OperationQueue讓您可以更好地控制操作的執行方式。 例如,您可以定義各個操作之間的依賴關系,這對於普通的 GCD 隊列是不可能的。 也可以取消已在 OperationQueue 中排隊的OperationQueue (只要操作支持它)。 當你在 GCD 調度隊列中加入一個塊時,它肯定會在某個時候被執行。

綜上所述, OperationQueue可以更適合可能需要取消或具有復雜依賴關系的長時間運行的操作。 GCD 調度隊列更適合應該具有最低性能和 memory 開銷的短任務。

  • 在任務不太復雜且需要最佳 CPU 性能的情況下,首選 GCD。
  • 首選 NSOperationQueue ,其中任務很復雜,需要取消或暫停塊和依賴管理

GCD 是一種輕量級的方式來表示將要同時執行的工作單元。 您不安排這些工作單元; 系統會為您安排日程。 在塊之間添加依賴關系可能會讓人頭疼。 作為開發人員,取消或暫停塊會為您帶來額外的工作!

與 GCD 相比,NSOperation 和 NSOperationQueue 增加了一點額外的開銷,但是您可以在各種操作之間添加依賴關系。 您可以重復使用操作、取消或暫停它們。 NSOperation 兼容 Key-Value Observation (KVO); 例如,您可以通過監聽 NSNotificationCenter 來開始運行 NSOperation。

NSOperation 和 NSOperationQueue 是更高級別的 API,建立在 GDC 本身之上,以面向 object 的方式實現並發。

詳細解釋參考這個問題:https://stackoverflow.com/questions/10373331/nsoperation-vs-grand-central-dispatch

關於 GCD 的一個常見誤解是“一旦你安排了一個不能取消的任務,你就需要為此使用 Operation API” 隨着 iOS 8 和 macOS 10.10 DispatchWorkItem被引入,它在一個易於使用的 API 中提供了這個確切的功能。

正如我在Apple 開發人員文檔中閱讀的DispatchQueue一樣,現在您可以取消執行任務。 為此,您必須在使用 GCD over OperationQueue 時使用DispatchWorkItem

-

調度工作項有一個取消標志。 如果它在運行之前被取消,調度隊列將不會執行它並會跳過它。 如果它在執行期間被取消,cancel 屬性返回 true。 在這種情況下,我們可以中止執行。 工作項也可以在其任務完成時通知隊列。

注意: GCD 不執行搶先取消。 要停止已經開始的工作項,您必須自己測試是否取消。

如下例所示,我檢查了以下代碼

if (task?.isCancelled)! {
    break
}

蘋果的定義

DispatchWorkItem 封裝要在調度隊列或調度組內執行的工作。 您還可以將工作項用作 DispatchSource 事件、注冊或取消處理程序。

我從SwiftIndia 的 Medium 帖子中獲取了以下示例。 有關更多詳細信息,請關注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")

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM