iOS 进程、线程、多线程、多进程... 的认识

iOS 进程、线程、多线程、多进程… 的认识

基于对进程、线程的记忆模糊,为了提高自己的认知,查找了许多许多资料,做了一次汇总。PS: 感谢广大网友。原文链接: 简书地址

一、进程

  • 进程是一个具有独立功能的程序关于某次数据集合的一次运行活动,他是操作系统分配资源的基本单位
  • 进程是指系统正在运行中的一个应用程序,就是一段程序执行的过程。我们可以理解为手机上的一个app。
  • 每个进程之间是独立的,每个进程均运行在起专用且受保护的内存空间内,拥有独立运行所需的全部资源。
  • 进程是操作系统进行资源分配的单位

二、线程

  • 程序执行流的最小单元,线程是进程中的一个实体

  • 一个进程想要执行任务,必须至少有一条线程。应用程序启动的时候,系统会默认开启一条线程,也就是主线程。

三、进程和线程的关系

  • 线程是进程的执行单元,进程的所有任务都在线程中执行。
  • 线程是CPU分配资源和调度的最小单位
  • 一个程序可对应多个进程(多进程);一个进程中可对应多个线程,但至少要有一条线程。
  • 同个进程内的线程共享进程资源。

四、多进程

  • 进程是程序在计算机上的一次执行活动。当你运行一个程序,你就启动了一个进程。显然程序是死的(静态的),进程是活动的(动态的)。
  • 进程可以分为系统进程用户进程
    • 系统进程:凡是用于完成操作系统的各种功能的进程就是系统进程,他们就是出于运行状态下的操作系统本身
    • 用户进程:运行用户程序时创建的运行在用户态下的进程。
  • 进程又被细化为线程,也就是一个进程下有多个能独立运行的更小的单位。在同一个时间里,同一个计算机系统中如果允许两个或两个以上的进程处于运行状态,这便是多进程。

五、多线程

  • 同一时间,CPU 只能处理1条线程,只有1条线程执行。多线程并发执行,其实是CPU快速地在多条线程之间调度(切换)。如果CPU的调度线程的时间足够快,就造成了多线程并发执行的假象。

  • 如果线程非常至多(N条),CPU会在这些(N条)线程之间调度,消耗大量的CPU资源,每条线程被调用执行的频率会降低(线程的执行效率降低)。

  • 多线程的有点:

    • 适当提高程序的执行效率
    • 适当提高资源的利用率(CPU、内存利用率)
  • 多线程的缺点:

    • 开启线程需要占用一定的内存空间(默认情况下,主线程占用1M,子线程占用512kb),如若开启大量线程,会占用大量的内存空间,就会降低程序的性能

    • 线程越多,CPU在调度线程的开销就越大

    • 程序设计更加复杂:如线程之间的通信、多线程之间的数据共享等

六、任务

就是执行操作的意思,也就是在线程中执行的那段代码。在DCD中是放在block 中的。

执行任务的方式有两种同步执行(sync)异步执行(async)

  • 同步(Sync): 同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列中的任务都完成之后再执行,所以会阻塞线程。 只能在当前线程中执行任务(是当前的线程,不一定是主线程),不具备开启新线程的能力

  • 异步(Async): 线程会立即返回,无需等待就会继续执行下面的任务,不会阻塞当前线程。可以在线的线程中执行任务,具备开启线程的能力(具备但不是一定要开启新线程)。如果不是添加在主队列上,异步会在子线程中执行任务。

七、 队列

队列(Dispatch Queue): 这里的队列是指执行任务的等待队列,即用来存放任务的队列

队列是一种特殊的线性表,遵循 FIFO(先进先出) 的原则,即只能在队尾插入,队头删除。 没读取一个任务,则从队列中释放(删除)一个任务。

在GCD中有两种队列:串行队列并发队列。两者都符合 FIFO 的原则,二者的主要区别是:执行的顺序不同开启的线程数不同

  • 串行队列(Serial Dispatch Queue):

    同一时间内,队列中只能执行一个任务,只有当前的任务执行完成之后,才能执行下一个任务。(只能开启一个线程,一个线程执行完毕后,再执行下一个任务)。主队列是主线程上的一个串行队列,是系统自动为程序创建的

  • 并行队列(Concurrent Dispatch Queue):

    同时允许多个任务同时执行。(可以开启多个线程,并且同时执行)。并发队列的并发功能只有在异步(dispatch_async) 函数下才有效

八、iOS 中的多线程

主要有三种:NSThread、NSOperationQueue、GCD

  1. NSThread: 轻量级别的多线程技术

    • 手动开辟的子线程,使用的是初始化方式:那么就需要我们自己启动

    • 手动开辟的子线程,使用的是构造器方式:那么它就会自动启动

    • 只要是我们手动开辟的子线程,都需要我们自己管理,包括该线程启动使用完毕后的资源回收

          NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(testThread:) object:@"我是参数"];
          // 当使用初始化方法出来的主线程需要start启动
          [thread start];
          // 可以为开辟的子线程起名字
          thread.name = @"NSThread线程";
          // 调整Thread的权限 线程权限的范围值为0 ~ 1 。越大权限越高,先执行的概率就会越高,由于是概率,所以并不能很准确的的实现我们想要的执行顺序,默认值是0.5
          thread.threadPriority = 1;
          // 取消当前已经启动的线程
          [thread cancel];
          // 通过遍历构造器开辟子线程
          [NSThread detachNewThreadSelector:@selector(testThread:) toTarget:self withObject:@"构造器方式"];
      
    • performSelector… 只要是 NSObject 的子类或者对象,都可以通过调用该方法进入子线程和主程。其实这些方法所开辟的子线程也是 NSThread 的另一种体现方式。

      注意:在编译阶段并不会去检查方式是否有效存在,如果不存在只会给出警告

            //在当前线程。延迟1s执行。响应了OC语言的动态性:延迟到运行时才绑定方法
              [self performSelector:@selector(aaa) withObject:nil afterDelay:1];
            // 回到主线程。waitUntilDone:是否将该回调方法执行完在执行后面的代码,如果为YES:就必须等回调方法执行完成之后才能执行后面的代码,说白了就是阻塞当前的线程;如果是NO:就是不等回调方法结束,不会阻塞当前线程
              [self performSelectorOnMainThread:@selector(aaa) withObject:nil waitUntilDone:YES];
            //开辟子线程
              [self performSelectorInBackground:@selector(aaa) withObject:nil];
            //在指定线程执行
              [self performSelector:@selector(aaa) onThread:[NSThread currentThread] withObject:nil waitUntilDone:YES]
      

      **需要注意的是:** 如果带有 afterDelay 延时参数时,会在内部创建一个 NSTimer , 然后添加到当前线程的 Runloop 中。也就是如果当前线程没有开启 runloop ,该方法就会失效。在子线程中,需要启动runloop(注意调用顺序)。

      [self performSelector:@selector(aaa) withObject:nil afterDelay:1];
      [[NSRunLoop currentRunLoop] run];
      

      perfromSelector:withObject: 只是一个单纯的消息发送,和时间没有关系,所以不需要添加在子线程的 runloop 也可以执行。

  2. GCD 对比 NSOperationQueue

二者之间的关系:

GCD 是面向底层的C语言的API, NSOperationQueue 使用 GCD 构建封装的,是GCD的高级抽象。

  • GCD 的执行效率更高。而且由于队列中执行的是由block构成的任务,这个一个轻量级的数据结构,写起来更方便
  • GCD 只支持FIFO的队列,而NSOperationQueue可以通过设置最大并发数设置优先级添加依赖关系等调整执行顺序
  • NSOperationQueue 甚至可以设置跨队列依赖关系,但是GCD 只能通过设置串行队列,或者在队列内添加barrier(dispaych_barrier_async)任务,才能控制执行顺序,较为复杂
  • NSOperationQueue 因为面向对象,所以支持KVO,可以检测 operation 是否正在执行(isExecuted)、是否结束(isFinished)、是否取消(isCanceld)
    • 实际项目中,很多时候只是用到异步操作,不会有特别复杂的线程关系管理,一所GCD 是苹果推荐的优选项
    • 如果考虑异步操作之间的事务性、顺序性、依赖关系,比如多线程并发下载,GCD需要写更多的代码,而NSOperationQueue 已经内建了这些支持
    • 不论是GCD 还是NSOperationQueue,我们接触的都是任务和队列,都没有直接接触到线程,事实上线程的管理也的确不需要我们操心,系统对于线程的创建,调度管理和释放都做得很好。而NSThread 需要我们自己去管理线程的生命周期,还要考虑线程的同步、加锁问题,造成一些性能上的开销。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值