美文网首页
多线程之3-OperationQueue

多线程之3-OperationQueue

作者: 栋柠柒 | 来源:发表于2021-11-23 22:53 被阅读0次

    Operation基于GCD封装, 完全面向对象. 对应于GCD, Operation也有任务和队列的概念, 只不过在Operation中任务(block)被称为操作(operation).
    Operation支持以下关键功能:

    1.操作之间添加依赖
    2.使用KVO监听操作的执行状态
    3.对操作进行优先级排序
    4.取消操作
    
    • 在GCD中, 任务代码只能写在block中, 并且需要放到队列(dispatch queue)中去执行.
    • 在Operation中, 操作对象可以单独执行, 也可以添加到队列 (operation queue)去执行.

    Operation是一个抽象类, 代表一个任务. 通常我们使用它的子类NSInvocationOperation或NSBlockOperation来编写任务代码. 当然也可以直接使用Operation, 不过需要重写main方法, 在main里面编写任务代码.

    1.创建方式

    • NSInvocationOperation (swift不支持): 此类调用选择器方法(selector), 在方法里面编写任务代码.
    • BlockOperation : 此类采用block方式, 在block中编写任务代码.
    • Operation: 需要继承Operation建立子类,重写main方法, 在main里面编写任务代码.

    2.执行方式

    • 不添加到队列, 手动调用operation的start方法.
    • 添加到队列, 系统自动调用start方法.

    3.同步异步

    Operation 没有 GCD 中的sync 和 async 方法。
    苹果文档
    如果计划手动执行操作对象,而不是将其添加到队列中,则可以将操作设计为以同步或异步方式执行。默认情况下,操作对象是同步的。当start()直接从代码中调用同步操作的方法时,该操作将在当前线程中立即执行。
    默认情况下,操作对象以同步方式执行-也就是说,它们在调用其start方法的线程中执行其任务。
    为了获得最佳性能,您应该将操作设计为尽可能异步,使应用程序在执行操作时可以自由地做其他工作。

    • 如果不使用OperationQueue, operation默认以同步方式执行. 但我们有办法使之异步执行: 新建一个新线程, 然后在新线程里面调用start方法.
    • 如果使用OperationQueue, 系统默认以异步方式执行. 但我们可以使用waitUntilAllOperationsAreFinished 进行等待, 以确保操作完成后才继续往下执行.

    4.队列(OperationQueue)

    队列 (Operation Queue)有两种: 主队列和非主队列 (自定义队列).

    • 主队列通过OperationQueue.main获得, 主队列里的任务都是放到主线程执行 (不包括使用addExecutionBlock:添加的额外操作, 因其可能在其他线程执行).
    • 非主队列 (自定义队列) 即一般 .init 出来的队列, 默认在子线程中异步执行. 通多设置最大并发数(maxConcurrentOperationCount)来控制队列是串行还是并发.

    添加操作(任务)到队列有四种方式:

    • addOperation: 添加一个现有的Operation (或者其子类).
    • addOperations:waitUntilFinished: 可添加多个现有的Operation (或者其子类), 可设置等待所有操作完成后方可继续往下执行.
    • addOperationWithBlock: 直接添加一个block
    • addBarrierBlock: 添加栅栏, 顺带一个任务. 等栅栏前的所有任务都执行完, 再执行本栅栏的任务, 起到隔离同步等待的目的.

    5.串行并行

    主队列是串行队列. 自定义队列默认是并发队列, 但可通多设置最大并发数(maxConcurrentOperationCount)来控制队列是串行还是并发.

    maxConcurrentOperationCount

    -1, 默认值, 并发队列;
    =0, 不执行任何操作;
    =1, 串行队列;
    <0, 除-1默认值外, 其他负值均报错;
    >1, 并发队列, 如果数值过大, 最终并发数由系统决定.

    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中, 调用start方法后, 系统会执行多项安全检查, 最终会调用main方法.

    2.使用 OperationQueue
    let operationQueue = OperationQueue() // 默认并发执行
            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)}
    
    设置最大并发数
    let operationQueue = OperationQueue() // 默认并发执行
            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() // 默认并发执行
            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.设置优先级
    public enum QueuePriority : Int {
    
            case veryLow = -8
    
            case low = -4
    
            case normal = 0
    
            case high = 4
    
            case veryHigh = 8
        }
    
    let operationQueue = OperationQueue() // 默认并发执行
            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() // 默认并发执行
            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开始执行之后,另外开辟了一条新线程执行的。

    相关文章

      网友评论

          本文标题:多线程之3-OperationQueue

          本文链接:https://www.haomeiwen.com/subject/sysgtrtx.html