多執行緒:Operation和OperationQueue

小小志偉發表於2018-11-18

多執行緒:實現方式Operation和OperationQueue

Operation

多執行緒:Operation和OperationQueue

生命週期

多執行緒:Operation和OperationQueue

//都有共同特點,只讀屬性。
//是否準備
open var isReady: Bool { get }
//是否執行
open var isExecuting: Bool { get }
//是否取消
open var isCancelled: Bool { get }
//是否完成
open var isFinished: Bool { get }
//操作完成之後的回撥
open var completionBlock: (() -> Void)?
複製程式碼
  1. let operation = Operation() 此時處於Pending狀態
  2. 依賴新增完會進入Ready階段。此時操作物件會進入準備就緒狀態
  3. 優先順序設定之後會進入執行階段。queuePriority屬性決定了進入準備就緒狀態下的操作之間的開始執行順序。
  4. 完成之後會finished,並且有回撥。
  5. 完成之後的不能取消,取消可以在其他三個時刻。

依賴(dependency)

//新增依賴
open func addDependency(_ op: Operation)
//移除依賴
open func removeDependency(_ op: Operation)
複製程式碼
//1.建立佇列
let queue = OperationQueue()
//2.建立操作
let op1 = BlockOperation {
    print("操作1")
}
let op2 = BlockOperation {
    print("操作2")
}
//3.新增依賴
op2.addDependency(op1)
//4.新增操作
queue.addOperation(op2)
queue.addOperation(op1)
複製程式碼

列印結果:

操作1
操作2
複製程式碼

結論是:op2依賴於op1時,不管新增操作的順序如何,結果都是op1先執行,op2再執行。

  1. 新增依賴,改變操作順序。 在SDWebImage中
  if (sself.executionOrder == SDWebImageDownloaderLIFOExecutionOrder) {
            // Emulate LIFO execution order by systematically adding new operations as last operation's dependency
            [sself.lastAddedOperation addDependency:operation];
            sself.lastAddedOperation = operation;
        }
複製程式碼
typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) {
    /**
     * Default value. All download operations will execute in queue style (first-in-first-out).
先進先出:這是佇列的資料結構
     */
    SDWebImageDownloaderFIFOExecutionOrder,

    /**
     * All download operations will execute in stack style (last-in-first-out).
後進先出:這是棧的資料結構
     */
    SDWebImageDownloaderLIFOExecutionOrder
};
複製程式碼

FIFO:先進先出:這是佇列的資料結構。
LIFO:這是棧的資料結構。
關於這兩個資料結構模型(暫且不講),因為後進的操作依賴於新進的操作,所以後進的操作要等先進的操作出隊之後在執行。
這就是根據依賴改變的佇列的執行順序。

  1. 不同佇列的操作可以依賴 。順序儲存不變。
  2. 不能相互依賴,會造成操作死鎖。

優先順序(queuePriority)

open var queuePriority: Operation.QueuePriority 預設normal

 public enum QueuePriority : Int {
        case veryLow
        case low
        case normal
        case high
        case veryHigh
    }
複製程式碼

NSOperation 提供了queuePriority(優先順序)屬性,queuePriority屬性適用於同一操作佇列中的操作,不適用於不同操作佇列中的操作。
在SDWebImage中

if (options & SDWebImageDownloaderHighPriority) {
            operation.queuePriority = NSOperationQueuePriorityHigh;
        } else if (options & SDWebImageDownloaderLowPriority) {
            operation.queuePriority = NSOperationQueuePriorityLow;
        }
複製程式碼

多執行緒:Operation和OperationQueue

取消操作

//取消操作
open func cancel()
複製程式碼

waitUntilFinished()

阻塞當前執行緒,直到該操作結束。可用於執行緒執行順序的同步。

        print("begain")
        let opA = BlockOperation()
        opA.addExecutionBlock {
            print("操作A")
        }
        let opB = BlockOperation()
        opB.addExecutionBlock {
            print("操作B")
        }
        
        let queue = OperationQueue()
        queue.addOperations([opA,opB], waitUntilFinished: true)
        print("------")
        
        let opC = BlockOperation()
        opC.addExecutionBlock {
            print("操作C")
        }
        let opD = BlockOperation()
        opD.addExecutionBlock {
            print("操作D")
        }
        queue.addOperations([opC,opD], waitUntilFinished: true)
        print("end")
複製程式碼

列印結果

begain
操作A
操作B
------
操作C
操作D
end
複製程式碼

直到操作A、操作B完成之後,才能進行下面的操作


operation的實現類

因為operation是抽象類,所以使用的時候需要用子類或者繼承operation的子類。

BlockOperation

        let opA = BlockOperation()
        opA.addExecutionBlock {
            print("操作A")
        }
複製程式碼

NSInvocationOperation

swfit中已經沒有這個類了,只在OC中。

繼承Operation

  • 非併發:non-concurrent
main()
複製程式碼

必須重寫main()方法

class DownLoadOperation: Operation {
    override func main() {
    print("下載了")
    }
}
複製程式碼
    let opA = DownLoadOperation()
    let queue = OperationQueue()
    queue.addOperations([opA], waitUntilFinished: true)
複製程式碼
  • 併發:concurrent
start()

isAsynchronous

isExecuting

isFinished
複製程式碼

至少這幾個屬性和方法重寫
可以看SDWebimage封裝的opeation


operation流程化

可以看出opretaion可以繼承類,所以取代了程式碼塊,更加物件導向。
opretaion的生命週期可以看出,操作更加容易控制。
依賴是邏輯流程更加清晰可控。所以流程化複雜的場景更合適。


operationQueue

多執行緒:Operation和OperationQueue
operation:操作,一個任務可以當做是一個操作。例如:下載任務,上傳任務,圖片編解碼任務,播放音視訊...都可以看做是一個操作。
operationQueue:操作佇列,這個操作佇列負責把放入佇列裡的操作,按照一定順序排程執行。

使用步驟

  • 例項化一個操作,注意:要是operation的子類。
  • 初始化queue
  • 把操作新增到佇列裡。

maxConcurrentOperationCount:最大操作併發數。

  • default:是一個併發佇列。
  • count=1:是一個序列佇列。
  • count>1:是一個併發佇列。
    雖然count可以控制併發數,但不是數量越多效率越高,受限於cpu的能力,一般6~8最適合。

引用

蘋果官方文件

深入淺出 iOS 併發程式設計

相關文章