基本概念
- 進程(Process):一個正在運行中的可執行文件。每個進程都有獨立的內存空間和系統資源(端口權限等),至少包含一個主線程和任意數量的其餘(輔)線程。當一個進程的主線程退出時,則該進程即結束了。
- 線程(Thread):一個獨立的代碼執行路徑,也即線程是代碼執行路徑的最小分支。iOS 中,線程底層基於 POSIX threads APIs,即 pthreads。
- 任務(Task):須要執行的工做(一段代碼),是個抽象概念。
- 串行 vs. 併發:主要區別在於容許同時執行的任務數量
-
- 串行:一次只能執行一個任務,必須等一個任務執行完成後才執行下一個任務。
- 併發:指容許多個任務同時執行。(note: 其實也是某一時刻只執行一個任務,系統在多個任務之間進行快速切換,區別於並行)
- 同步 vs. 異步:主要區別在因而否等待任務執行完成,便是否阻塞當前線程。
-
- 同步:會等待執行完成後再繼續執行接下來的代碼
- 異步:調用後當即返回,不會等待執行操做的執行結果
- 隊列 vs. 線程:
-
- 隊列:iOS 中,分爲串行隊列與併發隊列,用於處理不一樣須要的任務。
- 線程:iOS 系統使用隊列進行任務調度,根據任務須要和系統負載狀況動態地建立和銷燬線程,而無須手動管理。
iOS 的併發編程模型
在 iOS 中,蘋果與傳統的基於線程不一樣,而是採用隊列,通常只須要定義好調度的任務,並加入到相應的隊列,系統就會在合適的線程執行這些任務,而不須要關心線程的建立和銷燬。
如下情景應該直接使用線程:
- 用線程之外的方式沒法實現的特定任務
- 必須實時執行一個任務
- 對在後臺執行的任務有更多的可預測行爲
Operation Queues vs. Grand Central Dispatch (GCD)
- Operation Queues: 相對增長了一點開銷,更靈活,可經過給 operation 之間添加依賴關係,開始、暫停、恢復,或取消 operation
- GCD:輕量級,以 FIFO 的順序執行併發任務。使用 GCD 時,咱們不關心任務具體的調度狀況,而是由系統處理,所以也相對不夠靈活
關於 Operation 對象
用於封裝須要執行的任務,Operation 自己是一個抽象類,使用時必須建立自定義子類或使用系統預約義的子類,NSInvocationOperation 和 BlockOperation
- NSInvocationOperation: 經過一個 object 和 selector 建立一個非併發的(non-concurrent) operation(Swift 不可用,BlockOperation 或 OperationQueue.addOperation(block:) 替代)
- BlockOperation: 可用來併發執行一個或多個 block,只有當一個 BlockOperation 關聯的全部 block 執行完畢,這個 operation 纔算執行完畢,相似 dispatch_group
另外,全部 operation 都支持如下特性:
- 支持在 operation 之間創建依賴關係,只有當一個 operation 所依賴的全部 operation 都完成時,這個 operation 才能開始執行;
- 支持一個可選的 completion block,會在主任務執行完成時被調用;
- 支持經過 KVO 來觀察 operation 執行狀態的變化;
- 支持設置執行的優先級,從而影響 operation 之間的相對執行順序;
- 支持取消,能夠中止正在執行的 operation
併發 vs. 非併發 Operation
通常都是經過將 operation 添加到 operation queue 的方式來執行 operation,但這並非必須的,還能夠直接調用 start 方法來執行,但這種方式不能保證 operation 是異步執行的。Operation 類的 isConcurrent 方法的返回值標識了相對於調用 start 方法的線程是否異步執行,默認狀況下,isConcurrent 的返回值爲 false,即會阻塞調用 start 方法的線程。
自定義併發執行的 operation,須要編寫一些額外的代碼支持異步執行,如建立新線程,調用系統的異步方法或其餘方式確保 start 方法在開始執行任務後當即返回。但絕大多數狀況下,都是將 operation 添加到 operation queue 的方式來執行,所以不必實現併發的 operation。
建立 NSInvocationOperation
Swift 不可用,略。
建立 BlockOperation
let blockOperation = BlockOperation(block: {
print("start excute block1")
sleep(1)
print("finish block1")
})
blockOperation.addExecutionBlock {
print("start excute block2")
sleep(1)
print("finish block2")
}
blockOperation.addExecutionBlock {
print("start excute block3")
sleep(1)
print("finish block3")
}
blockOperation.start()複製代碼
* 異步執行,blocks 開始與結束的順序不肯定
自定義 Operation 對象
- 非併發 Operation 子類
-
- 執行 main 方法中的主任務
- 響應取消事件:
-
- 儘管 operation 是支持取消操做的,但卻並非當即取消的,而是在你調用了 operation 的 cancel 方法以後的下一個 isCancelled 的檢查點取消的。
- 併發 Operation 子類額外配置:
-
- 重寫 start 方法,而且必定不要調用父類的實現
- 重寫 isExecuting 和 isFinished,維護這兩個狀態,並生成響應的 KVO 通知
- 重寫 isConcurrent,返回 true.
注意! 即便一個 operation 是被 cancel 掉了,仍需手動觸發 isFinished 的 KVO 通知。由於 operation 依賴會觀察其 isFinished 值變化。
維護 KVO 通知
Operation 類如下 Key Path 支持 KVO 通知:
- isConcurrent
- isExecuting
- isFinished
- isReady
- dependencies
- queuePriority
- completionBlock
定製 Operation 對象的行爲
Operation 的靈活性就體如今執行行爲的可定製
- 配置(單向)依賴關係
-
- addDependency(op:)
- removeDependency(op:)
- 與 operation queue 無關
- 注意!不要循環依賴,不然永遠不會執行
- 在手動執行或添加到 operation queue 以前配置好依賴關係,不然可能會失效
- 修改 Operation 在隊列中的優先級
-
- .queuePriority
- 第一要素是 operation 的 isReady 狀態(取決於依賴關係)
- 其次即 operation 在隊列中的優先級
- 默認優先級 normal
- 應用於相對的 operation queue
- 修改 Operation 在線程中的優先級(iOS 8.0 廢棄,新增 qualityOfService 替代)
-
- .threadPriority
- 默認的 start 方法會修改它的線程優先級
- 隻影響 main 方法執行所在線程
- 自定義併發 operation 子類時在 start 方法中也要根據指定的值修改當前線程的優先級
- 設置 Completion Block
-
- .completionBlock
- 注意!operation 被取消時,completion block 也會執行
- 沒法保證在主線程執行
執行 Operation
- 將 operation 添加到一個 operation queue,自動執行
-
- 建立 OperationQueue 對象實例
- 添加 operation
-
- addOperation(op: Operation)
- addOperations(ops: [Operation], waitUntilFinished: Bool)
- addOperation(block: )
- operation 添加到 operation queue 了就不要再修改了
- 直接調用 start 方法手動執行
-
取消 Operation
operation 加入 operation queue 後,惟一 dequeue 的辦法就是調用 operation 的 cancel 方法
等待 Operation 結束
OperationQueue 的 addOperations(ops: [Operation], waitUntilFinished: Bool) 和 Operation 的 waitUntilFinished 方法用於阻塞當前線程,直到相關 operation 執行結束。
注意!避免阻塞主線程。
暫停和恢復 Operation Queue
暫停隊列並不能暫停正在執行的 operation,只是暫停調度新的 operation
更多參考