• 多线程:Operation(一)


    1. 进程和线程

    1.1 进程

    • 进程:正在运行的应用程序叫进程
    • 进程之间都是独立的,运行在专用且受保护的内存空间中
    • 两个进程之间无法通讯

    通俗的理解,手机上同时开启了两个App。这两个App肯定是在不同的进程中的。所以这两个App之间是独立的,内存中的数据不能互相窜来窜去,两个App之间也没有办法进行通讯。

    两个App之间没有办法进行通讯?我说的是正常情况下。当然还是有不正常情况啊,例如使用iOS提供的极少数的几种进程间通讯的工具。

    1.2 线程

    • 线程:进程想要执行任务,必须要有线程,每个进程至少有一条线程。
    • 线程就是用来干活的。
    • 程序一启动,就会启动进程。进程默认开启一条线程。

    干活的线程?对啊,活太多,或者不想彼此互相等着浪费时间,当然可以找几个人同时干了。
    例如在项目上,产品经理需求都没有完全写完,也不妨碍先设计一个大概的数据框架啊。例如需求没有完全定下来,不妨碍UI童鞋提前设计啊,大不了再改嘛~ HOHO~怎么听上去都像是黑话。

    1.3 多线程

    • 单核CPU同一时间,CPU只能处理1个线程,只有1个线程在执行任务。

    • 多线程的同时执行 : 其实是CPU在多条线程之间快速切换(调度任务)。

    • 如果CPU调度线程的速度足够快,就造成了多线程同时执行的假象

    • 如果线程非常多,CPU会在多条线程之间不断的调度任务,结果就是消耗了大量的CPU资源,效率下降:

      • 每个线程调度的频率会降低
      • 线程的执行效率会下降

    iPhone手机是几核的?
    A7 : iPhone 5S , 双核
    A8: iPhone 6、iPhone 6 Plus,双核
    A9:iPhone 6S、iPhone 6S Plus,双核
    A10:iPhone 7、iPhone 7 Plus,2+2核

    1.4 iOS中的多线程

    刚才说了,iOS App一旦运行,默认就会开启一条线程。这条线程,我们通常称作为“主线程

    主线程的作用:

    1. 刷新UI
    2. 处理UI事件,例如点击、滚动、拖拽。

    如果主线程的操作太多、太耗时,就会造成App卡顿现象严重。所以,通常我们都会把耗时的操作放在子线程中进行,获取到结果之后,回到主线程去刷新UI。

    2. Operation

    我们来看看基础使用:

     1 //    最基本的使用Operation
     2     private func basicOperation() {
     3 //        第一步:创建Operation
     4         let op = Operation.init()
     5 //        第二步:把要执行的代码放入operation中
     6         op.completionBlock = {
     7         
     8             print(#function,#line,Thread.current)
     9         }
    10 //        第三步:创建OperationQueue
    11         let opQueue = OperationQueue.init()
    12 //        第四步:把Operation加入到线程中
    13         opQueue.addOperation(op)
    14     }

    使用BlockOperation创建operatoin,并直接运行。咱们看看会在哪条线程执行。

     1 //创建一个简单的BlockOperation
     2 private func CreatBasicBlockOperation() {
     3     //使用BlockOperation创建operation
     4     let operation = BlockOperation.init {
     5         //打印,看看在哪个线程中
     6         
     7         print(#function,#line,Thread.current)
     8     }
     9     
    10     //直接运行operation,看看运行在哪个线程中
    11     operation.start()
    12 }
    

    打印一下看看运行的结果:

    这就是我们说,创建完Operation如果直接运行,就会在当前线程执行。也就是说,如果实在主线程创建并且start的,那就会在主线程执行;如果是在子线程创建并且start的,那就会在子线程执行。

    3. Basic Demo

    在这个例子里面,需求如下:
    1,在子线程加载每个图片的数据
    2,图片数据下载完毕之后,显示出来
    3,开始请求数据的时候,让指示符开始转动
    4,所有图片下载完毕后,指示符停止转动

    3. Basic Demo

    在这个例子里面,需求如下:
    1,在子线程加载每个图片的数据
    2,图片数据下载完毕之后,显示出来
    3,开始请求数据的时候,让指示符开始转动
    4,所有图片下载完毕后,指示符停止转动

    3.2 Swift中的do catch

    这个是Swift和OC不一样的地方。Swift中出现了可选值这么一个东西,这个不是这次的重点。想深入了解的童鞋可以参看这篇:?和 !的使用

    Swift 里有四种方法来处理错误:

    1. 把错误从函数传递到调用函数的代码里
    2. 使用一个 do-catch 语句来处理错误
    3. 把错误当做一个可选值来处理
    4. 断言这个错误不会发生

    因为Demo里面用到了do catch,那咱们就只说do catch.
    在Swift的标准try中,是要配合do catch的。

    下面是do-catch语句的一般格式,如果do分句内的代码抛出了一个错误,它就被catch分句捕获,并判断由哪个分句来处理此错误。

    1 do {
    2     try expression
    3     statements
    4 } catch pattern 1 {
    5     statements
    6 } catch pattern 2 where condition {
    7     statements
    8 }

    3.3 优先级

    在思维导图里面出现了两个优先级。一个是属于Operation 的,一个是属于OperationQueue的。那咱们分看看看这两个都是啥。

    3.3.1 Operation中的优先级

    Operation里面的这个叫做qualityOfService

    1 public enum QualityOfService : Int {
    2     case userInteractive
    3     case userInitiated    
    4     case utility    
    5     case background    
    6     case `default`
    7 }
    1 userInteractive:最高优先级,用于用户交互事件
    2 userInitiated :次高优先级,用于用户需要马上执行的事件
    3 utility:普通优先级,用于普通任务
    4 background:最低优先级,用于不重要的任务
    5 default:默认优先级,主线程和没有设置优先级的线程都默认为这个优先级

    3.3.2 operationQueue 里面的优先级

    operationQueue中表示优先级的属性是queuePriority,表示操作在队列中的优先级。

    1 public enum QueuePriority : Int {
    2     case veryLow
    3     case low
    4     case normal
    5     case high
    6     case veryHigh
    7 }

    这些优先级都是相对的,并不是是说必须要执行完最高的才执行次重要的。这里面并没有一个特别严格顺序。只是在分配资源上有倾向性。如果队列需要有严格的执行顺序,还是要添加依赖关系的,这个是我们下一篇文章要分享的内容。

    4. 案例实现

    Operation 基本应用及优先级小案例。
    实现后效果如下:

     

    这个Demo里面,用了两种方法创建Operation。

    startBasicDemo,使用的是闭包创建Operation的方式。在startPriorityDemo里面使用的是自定义的构造方法创建的Operation,然后把任务数组加入到线程中。

    代码:

     1 //    Operation 案例
     2     fileprivate func startBasicDemo()
     3     {
     4         let operationQueue = OperationQueue.init()
     5         operationQueue.maxConcurrentOperationCount = 3
     6         
     7         let activityIndicator = UIActivityIndicatorView()
     8         activityIndicator.startAnimating()
     9         
    10         let a = UIImageView(frame: CGRect(x: 0, y: 64,  414, height: 100))
    11         self.view.addSubview(a)
    12         let b = UIImageView(frame: CGRect(x: 0, y: 164,  414, height: 100))
    13         self.view.addSubview(b)
    14         let c = UIImageView(frame: CGRect(x: 0, y: 264,  414, height: 100))
    15         self.view.addSubview(c)
    16         let d = UIImageView(frame: CGRect(x: 0, y: 364,  414, height: 100))
    17         self.view.addSubview(d)
    18         
    19         
    20         let imageViews = [a, b, c, d]
    21         for imageView in imageViews {
    22             if let url = URL(string: "https://placebeard.it/355/140")
    23             {
    24                 do {
    25                     let image = UIImage(data:try Data(contentsOf: url))
    26                     
    27                     DispatchQueue.main.async
    28                         {
    29                             imageView.image = image
    30                         }
    31                 }catch
    32                 {
    33                     print(error)
    34                 }
    35             }
    36         }
    37 //        global queue
    38         DispatchQueue.global().async
    39             {
    40                 [weak self] in
    41 //            等待所有操作都完成了,回到主线程停止刷新器。
    42 //            wait Until All Operations are finished, then stop animation of activity indicator
    43                 operationQueue.waitUntilAllOperationsAreFinished()
    44                 DispatchQueue.main.async
    45                 {
    46                     activityIndicator.stopAnimating()
    47                  }
    48     
    49             }
    50 }
    View Code

    设置了优先级的Demo:

     1 fileprivate func startPriorityDemo() {
     2     operationQueue.maxConcurrentOperationCount = 2
     3     activityIndicator.startAnimating()
     4     
     5     var operations = [Operation]()
     6     for (index, imageView) in (imageViews?.enumerated())! {
     7         if let url = URL(string: "https://placebeard.it/355/140") {
     8             //                使用构造方法创建operation
     9             let operation = convenienceOperation(setImageView: imageView, withURL: url)
    10             
    11             //根据索引设置优先级
    12             switch index {
    13             case 0:
    14                 operation.queuePriority = .veryHigh
    15             case 1:
    16                 operation.queuePriority = .high
    17             case 2:
    18                 operation.queuePriority = .normal
    19             case 3:
    20                 operation.queuePriority = .low
    21             default:
    22                 operation.queuePriority = .veryLow
    23             }
    24             
    25             operations.append(operation)
    26         }
    27     }
    28     
    29     //        把任务数组加入到线程中
    30     DispatchQueue.global().async {
    31         [weak self] in
    32         self?.operationQueue.addOperations(operations, waitUntilFinished: true)
    33         DispatchQueue.main.async {
    34             self?.activityIndicator.stopAnimating()
    35         }
    36     }
    37     
    38 }
    View Code
  • 相关阅读:
    Java jni字符串转换
    Python读取PE文件(exe/dll)中的时间戳
    深度学习word embedding猜测性别初探
    闪存内容汇编(截止20170405)
    如何自动化安装字体(命令行批量)
    如何分析进程的内存占用问题
    Python print报ascii编码异常的靠谱解决办法
    Linux界面自动化测试框架不完全汇总
    Qt实现同步(阻塞式)http get等网络访问操作
    基于第三方开源库的OPC服务器开发指南(4)——后记:与另一个开源库opc workshop库相关的问题
  • 原文地址:https://www.cnblogs.com/EchoHG/p/7675846.html
Copyright © 2020-2023  润新知