基本概念
- 进程(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
更多参考