iOS多线程之超实用理论+demo演示(可下载)

[toc]

背景简介

     在初学iOS相关知识过程中,大多都对多线程有些恐惧的心里,同时感觉工作中用上的概率不大。但是如果平时不多积累并学透多线程,当工作中真的需要用到的时候,就很可能简单百度后把一些知识点稀里糊涂地就用到工作中了,殊不知里面有很多的坑,也有很多技巧需要在理论上先做了解,再结合实战,进一步去体会多线程的魅力和强大。

     接下来,就对多线程来源的背景进行简单的介绍:

     在计算的早期,计算机可以执行的最大工作量是由 CPU 的时钟速度决定的。但是随着技术的进步和处理器设计的紧凑化,热量和其他物理约束开始限制处理器的最大时钟速度。因此,芯片制造商寻找其他方法来提高芯片的总体性能。他们决定的解决方案是增加每个芯片上的处理器核心数量。通过增加内核的数量,一个单独的芯片可以每秒执行更多的指令,而不用增加 CPU 的速度或改变芯片的大小或热特性。唯一的问题是如何利用额外的内核。

     应用程序使用多核的传统方法是创建多个线程。与依赖线程不同,iOS 采用异步设计方法来解决并发问题。通常,这项工作涉及获取一个后台线程,在该线程上启动所需的任务,然后在任务完成时向调用方发送通知(通常通过一个回调函数)。

     iOS 提供了一些技术,允许您异步执行任何任务,而无需自己管理线程。异步启动任务的技术之一是 Grand Central Dispatch (GCD)。这种技术采用线程管理代码,并将该代码移动到系统级别。您所要做的就是定义要执行的任务,并将它们添加到适当的分派队列中。GCD 负责创建所需的线程,并安排任务在这些线程上运行。由于线程管理现在是系统的一部分,GCD 提供了任务管理和执行的整体方法,比传统线程提供了更高的效率。

     OperationQueue(操作队列,api 类名为 NSOperationQueue )是 Objective-C 对象,是对 GCD 的封装。其作用非常类似于分派队列。您定义要执行的任务,然后将它们添加到 OperationQueue 中, OperationQueue 处理这些任务的调度和执行。与 GCD 一样, OperationQueue 为您处理所有线程管理,确保在系统上尽可能快速有效地执行任务。

     接下来,就对现在工作中常用的这两种技术进行比较和实例解析。

GCD、OperationQueue 对比

核心理念

  • GCD的核心概念:将 任务(block) 添加到队列,并且指定执行任务的函数。
  • NSOperation 的核心概念:把 操作(异步) 添加到 队列。

区别

  • GCD:

    • 将任务(block)添加到队列(串行/并发/主队列),并且指定任务执行的函数(同步/异步)
    • GCD是底层的C语言构成的API
    • iOS 4.0 推出的,针对多核处理器的并发技术
    • 在队列中执行的是由 block 构成的任务,这是一个轻量级的数据结构
    • 要停止已经加入 queue 的 block 需要写复杂的代码
    • 需要通过 Barrier(dispatch_barrier_async)或者同步任务设置任务之间的依赖关系
    • 只能设置队列的优先级
    • 高级功能: dispatch_once_t(一次性执行, 多线程安全); dispatch_after(延迟); dispatch_group(调度组); dispatch_semaphore(信号量); dispatch_apply(优化顺序不敏感大体量for循环);
  • OperationQueue:

    • OC 框架,更加面向对象,是对 GCD 的封装。

    • iOS 2.0 推出的,苹果推出 GCD 之后,对 NSOperation 的底层进行了全部重写。

    • 可以设置队列中每一个操作的 QOS() 队列的整体 QOS

    • 操作相关 Operation作为一个对象,为我们提供了更多的选择: 任务依赖(addDependency),可以跨队列设置操作的依赖关系; 在队列中的优先级(queuePriority) 服务质量(qualityOfService, iOS8+); 完成回调(void (^completionBlock)(void)

    • 队列相关 服务质量(qualityOfService, iOS8+); 最大并发操作数(maxConcurrentOperationCount),GCD 不易实现; 暂停/继续(suspended); 取消所有操作(cancelAllOperations); KVO 监听队列任务执行进度(progress, iOS13+);

     接下来通过文字,结合实践代码(工程链接在文末)和运行效果 gif 图对部分功能进行分析。

GCD

队列

串行队列(Serial Queues)

     串行队列中的任务按顺序执行;但是不同串行队列间没有任何约束; 多个串行队列同时执行时,不同队列中任务执行是并发的效果。比如:火车站买票可以有多个卖票口,但是每个排的队都是串行队列,整体并发,单线串行。

     注意防坑:串行队列创建的位置。比如下面代码示例中:在for循环内部创建时,每个循环都是创建一个新的串行队列,里面只装一个任务,多个串行队列,结果整体上是并发的效果。想要串行效果,必须在for循环外部创建串行队列。

     串行队列适合管理共享资源。保证了顺序访问,杜绝了资源竞争。

      代码示例:

    private func serialExcuteByGCD(){
        let lArr : [UIImageView] = [imageView1, imageView2, imageView3, imageView4]

        //串行队列,异步执行时,只开一个子线程
        let serialQ = DispatchQueue.init(label: "com.companyName.serial.downImage")

        for i in 0..<lArr.count{
            let lImgV = lArr[i]

            //清空旧图片
            lImgV.image = nil

         //注意,防坑:串行队列创建的位置,在这创建时,每个循环都是一个新的串行队列,里面只装一个任务,多个串行队列,整体上是并行的效果。
            //            let serialQ = DispatchQueue.init(label: "com.companyName.serial.downImage")

            serialQ.async {

                print("第\(i)个 开始,%@",Thread.current)
                Downloader.downloadImageWithURLStr(urlStr: imageURLs[i]) { (img) in
                    let lImgV = lArr[i]

                    print("第\(i)个 结束")
                    DispatchQueue.main.async {
                        print("第\(i)个 切到主线程更新图片")
                        lImgV.image = img
                    }
  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值