多線程之3-OperationQueue

Operation基于GCD封裝, 完全面向?qū)ο? 對應(yīng)于GCD, Operation也有任務(wù)和隊列的概念, 只不過在Operation中任務(wù)(block)被稱為操作(operation).
Operation支持以下關(guān)鍵功能:

1.操作之間添加依賴
2.使用KVO監(jiān)聽操作的執(zhí)行狀態(tài)
3.對操作進行優(yōu)先級排序
4.取消操作
  • 在GCD中, 任務(wù)代碼只能寫在block中, 并且需要放到隊列(dispatch queue)中去執(zhí)行.
  • 在Operation中, 操作對象可以單獨執(zhí)行, 也可以添加到隊列 (operation queue)去執(zhí)行.

Operation是一個抽象類, 代表一個任務(wù). 通常我們使用它的子類NSInvocationOperation或NSBlockOperation來編寫任務(wù)代碼. 當(dāng)然也可以直接使用Operation, 不過需要重寫main方法, 在main里面編寫任務(wù)代碼.

1.創(chuàng)建方式

  • NSInvocationOperation (swift不支持): 此類調(diào)用選擇器方法(selector), 在方法里面編寫任務(wù)代碼.
  • BlockOperation : 此類采用block方式, 在block中編寫任務(wù)代碼.
  • Operation: 需要繼承Operation建立子類违施,重寫main方法, 在main里面編寫任務(wù)代碼.

2.執(zhí)行方式

  • 不添加到隊列, 手動調(diào)用operation的start方法.
  • 添加到隊列, 系統(tǒng)自動調(diào)用start方法.

3.同步異步

Operation 沒有 GCD 中的sync 和 async 方法够颠。
蘋果文檔
如果計劃手動執(zhí)行操作對象膨处,而不是將其添加到隊列中,則可以將操作設(shè)計為以同步或異步方式執(zhí)行。默認情況下隶症,操作對象是同步的咙好。當(dāng)start()直接從代碼中調(diào)用同步操作的方法時渡蜻,該操作將在當(dāng)前線程中立即執(zhí)行辑莫。
默認情況下学歧,操作對象以同步方式執(zhí)行-也就是說,它們在調(diào)用其start方法的線程中執(zhí)行其任務(wù)各吨。
為了獲得最佳性能枝笨,您應(yīng)該將操作設(shè)計為盡可能異步,使應(yīng)用程序在執(zhí)行操作時可以自由地做其他工作揭蜒。

  • 如果不使用OperationQueue, operation默認以同步方式執(zhí)行. 但我們有辦法使之異步執(zhí)行: 新建一個新線程, 然后在新線程里面調(diào)用start方法.
  • 如果使用OperationQueue, 系統(tǒng)默認以異步方式執(zhí)行. 但我們可以使用waitUntilAllOperationsAreFinished 進行等待, 以確保操作完成后才繼續(xù)往下執(zhí)行.

4.隊列(OperationQueue)

隊列 (Operation Queue)有兩種: 主隊列和非主隊列 (自定義隊列).

  • 主隊列通過OperationQueue.main獲得, 主隊列里的任務(wù)都是放到主線程執(zhí)行 (不包括使用addExecutionBlock:添加的額外操作, 因其可能在其他線程執(zhí)行).
  • 非主隊列 (自定義隊列) 即一般 .init 出來的隊列, 默認在子線程中異步執(zhí)行. 通多設(shè)置最大并發(fā)數(shù)(maxConcurrentOperationCount)來控制隊列是串行還是并發(fā).

添加操作(任務(wù))到隊列有四種方式:

  • addOperation: 添加一個現(xiàn)有的Operation (或者其子類).
  • addOperations:waitUntilFinished: 可添加多個現(xiàn)有的Operation (或者其子類), 可設(shè)置等待所有操作完成后方可繼續(xù)往下執(zhí)行.
  • addOperationWithBlock: 直接添加一個block
  • addBarrierBlock: 添加?xùn)艡? 順帶一個任務(wù). 等柵欄前的所有任務(wù)都執(zhí)行完, 再執(zhí)行本柵欄的任務(wù), 起到隔離同步等待的目的.

5.串行并行

主隊列是串行隊列. 自定義隊列默認是并發(fā)隊列, 但可通多設(shè)置最大并發(fā)數(shù)(maxConcurrentOperationCount)來控制隊列是串行還是并發(fā).

maxConcurrentOperationCount

-1, 默認值, 并發(fā)隊列;
=0, 不執(zhí)行任何操作;
=1, 串行隊列;
<0, 除-1默認值外, 其他負值均報錯;
>1, 并發(fā)隊列, 如果數(shù)值過大, 最終并發(fā)數(shù)由系統(tǒng)決定.

6.基本用法

1.不使用 OperationQueue
// block operation
let blockOperation = BlockOperation {
            for _ in 0...3 {
                print("blockOperation:\(Thread.current)")
            }
        }
        blockOperation.start()
//Operation
class CustomOperation: Operation {
    override func main() {
        print("\(#function), thread:\(Thread.current)")
    }
}

在自定義Operation中, 調(diào)用start方法后, 系統(tǒng)會執(zhí)行多項安全檢查, 最終會調(diào)用main方法.

2.使用 OperationQueue
let operationQueue = OperationQueue() // 默認并發(fā)執(zhí)行
        let blockOperation = BlockOperation {
            for _ in 0...3 {
                print("blockOperation:\(Thread.current)")
            }
        }
        let blockOperationItem = BlockOperation {
            for _ in 0...3 {
                print("blockOperationItem:\(Thread.current)")
            }
        }
        operationQueue.addOperation(blockOperation)
        operationQueue.addOperation(blockOperationItem)
blockOperationItem:<NSThread: 0x600001d8e400>{number = 3, name = (null)}
blockOperation:<NSThread: 0x600001d98080>{number = 6, name = (null)}
blockOperation:<NSThread: 0x600001d98080>{number = 6, name = (null)}
blockOperationItem:<NSThread: 0x600001d8e400>{number = 3, name = (null)}
blockOperation:<NSThread: 0x600001d98080>{number = 6, name = (null)}
blockOperationItem:<NSThread: 0x600001d8e400>{number = 3, name = (null)}
blockOperation:<NSThread: 0x600001d98080>{number = 6, name = (null)}
blockOperationItem:<NSThread: 0x600001d8e400>{number = 3, name = (null)}
設(shè)置最大并發(fā)數(shù)
let operationQueue = OperationQueue() // 默認并發(fā)執(zhí)行
        operationQueue.maxConcurrentOperationCount = 1
        let blockOperation = BlockOperation {
            for _ in 0...3 {
                print("blockOperation:\(Thread.current)")
            }
        }
        let blockOperationItem = BlockOperation {
            for _ in 0...3 {
                print("blockOperationItem:\(Thread.current)")
            }
        }
        operationQueue.addOperation(blockOperation)
        operationQueue.addOperation(blockOperationItem)
blockOperation:<NSThread: 0x6000021b4a00>{number = 3, name = (null)}
blockOperation:<NSThread: 0x6000021b4a00>{number = 3, name = (null)}
blockOperation:<NSThread: 0x6000021b4a00>{number = 3, name = (null)}
blockOperation:<NSThread: 0x6000021b4a00>{number = 3, name = (null)}
blockOperationItem:<NSThread: 0x6000021faac0>{number = 4, name = (null)}
blockOperationItem:<NSThread: 0x6000021faac0>{number = 4, name = (null)}
blockOperationItem:<NSThread: 0x6000021faac0>{number = 4, name = (null)}
blockOperationItem:<NSThread: 0x6000021faac0>{number = 4, name = (null)}
7.添加依賴

addDependency

let operationQueue = OperationQueue() // 默認并發(fā)執(zhí)行
        operationQueue.maxConcurrentOperationCount = 1
        let blockOperation = BlockOperation {
            for _ in 0...3 {
                print("blockOperation:\(Thread.current)")
            }
        }
        let blockOperationItem = BlockOperation {
            for _ in 0...3 {
                print("blockOperationItem:\(Thread.current)")
            }
        }
        let blockOperationItem2 = BlockOperation {
            print("blockOperationItem2:\(Thread.current)")
        }
        blockOperationItem2.addDependency(blockOperationItem)
        operationQueue.addOperation(blockOperation)
        operationQueue.addOperation(blockOperationItem)
        operationQueue.addOperation(blockOperationItem2)
8.設(shè)置優(yōu)先級
public enum QueuePriority : Int {

        case veryLow = -8

        case low = -4

        case normal = 0

        case high = 4

        case veryHigh = 8
    }
let operationQueue = OperationQueue() // 默認并發(fā)執(zhí)行
        operationQueue.maxConcurrentOperationCount = 2
        let blockOperation = BlockOperation {
            for _ in 0...3 {
                print("blockOperation:\(Thread.current)")
            }
        }
        let blockOperationItem = BlockOperation {
            for _ in 0...3 {
                print("blockOperationItem:\(Thread.current)")
            }
        }
        let blockOperationItem2 = BlockOperation {
            print("blockOperationItem2:\(Thread.current)")
        }
        blockOperationItem2.addDependency(blockOperationItem)
        blockOperationItem.queuePriority = .veryHigh
        blockOperation.queuePriority = .low
        operationQueue.addOperation(blockOperation)
        operationQueue.addOperation(blockOperationItem)
        operationQueue.addOperation(blockOperationItem2)
blockOperationItem:<NSThread: 0x6000032979c0>{number = 6, name = (null)}
blockOperation:<NSThread: 0x600003298100>{number = 4, name = (null)}
blockOperation:<NSThread: 0x600003298100>{number = 4, name = (null)}
blockOperation:<NSThread: 0x600003298100>{number = 4, name = (null)}
blockOperation:<NSThread: 0x600003298100>{number = 4, name = (null)}
blockOperationItem:<NSThread: 0x6000032979c0>{number = 6, name = (null)}
blockOperationItem:<NSThread: 0x6000032979c0>{number = 6, name = (null)}
blockOperationItem:<NSThread: 0x6000032979c0>{number = 6, name = (null)}
blockOperationItem2:<NSThread: 0x6000032979c0>{number = 6, name = (null)}
9. 通過addExecutionBlock方法添加block操作
let operationQueue = OperationQueue() // 默認并發(fā)執(zhí)行
        operationQueue.maxConcurrentOperationCount = 2
        let blockOperation = BlockOperation {
            for _ in 0...3 {
                print("blockOperation:\(Thread.current)")
            }
        }
        let blockOperationItem = BlockOperation {
            for _ in 0...3 {
                print("blockOperationItem:\(Thread.current)")
            }
        }
        blockOperationItem.addExecutionBlock {
            for _ in 0...2 {
                print("blockOperationItem addExecutionBlock:\(Thread.current)")
            }
        }
        operationQueue.addOperation(blockOperation)
        operationQueue.addOperation(blockOperationItem)
blockOperation:<NSThread: 0x6000028be9c0>{number = 7, name = (null)}
blockOperationItem:<NSThread: 0x6000028be700>{number = 5, name = (null)}
blockOperationItem addExecutionBlock:<NSThread: 0x6000028c4100>{number = 6, name = (null)}
blockOperationItem addExecutionBlock:<NSThread: 0x6000028c4100>{number = 6, name = (null)}
blockOperationItem addExecutionBlock:<NSThread: 0x6000028c4100>{number = 6, name = (null)}
blockOperationItem:<NSThread: 0x6000028be700>{number = 5, name = (null)}
blockOperation:<NSThread: 0x6000028be9c0>{number = 7, name = (null)}
blockOperationItem:<NSThread: 0x6000028be700>{number = 5, name = (null)}
blockOperation:<NSThread: 0x6000028be9c0>{number = 7, name = (null)}
blockOperationItem:<NSThread: 0x6000028be700>{number = 5, name = (null)}
blockOperation:<NSThread: 0x6000028be9c0>{number = 7, name = (null)}

可以看到横浑,通過addExecutionBlock 方法添加的代碼塊是在blockOperationItem開始執(zhí)行之后,另外開辟了一條新線程執(zhí)行的屉更。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末徙融,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子瑰谜,更是在濱河造成了極大的恐慌欺冀,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件萨脑,死亡現(xiàn)場離奇詭異隐轩,居然都是意外死亡,警方通過查閱死者的電腦和手機渤早,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門职车,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鹊杖,你說我怎么就攤上這事悴灵。” “怎么了骂蓖?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵积瞒,是天一觀的道長。 經(jīng)常有香客問我涯竟,道長赡鲜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任庐船,我火速辦了婚禮银酬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘筐钟。我一直安慰自己揩瞪,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布篓冲。 她就那樣靜靜地躺著李破,像睡著了一般宠哄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嗤攻,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天毛嫉,我揣著相機與錄音,去河邊找鬼妇菱。 笑死承粤,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的闯团。 我是一名探鬼主播辛臊,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼房交!你這毒婦竟也來了彻舰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤候味,失蹤者是張志新(化名)和其女友劉穎刃唤,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體负溪,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡透揣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年济炎,在試婚紗的時候發(fā)現(xiàn)自己被綠了川抡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡须尚,死狀恐怖崖堤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情耐床,我是刑警寧澤密幔,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站撩轰,受9級特大地震影響胯甩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜堪嫂,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一偎箫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧皆串,春花似錦淹办、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽速挑。三九已至,卻和暖如春副硅,著一層夾襖步出監(jiān)牢的瞬間姥宝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工恐疲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留伶授,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓流纹,卻偏偏與公主長得像糜烹,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子漱凝,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容