基于python线程、进程、协程思考

进程用来解决什么的
  程序是运行在系统上的具有某种功能的软件,比如说浏览器,音乐播放器等。 每次执行程序的时候,都会完成一定的功能,比如说浏览器帮我们打开网页,为了保证其独立性,就需要一个专门的管理和控制执行程序的数据结构——进程控制块。 进程就是一个程序在一个数据集上的一次动态执行过程。 进程一般由程序、数据集、进程控制块三部分组成。我们编写的程序用来描述进程要完成哪些功能以及如何完成;数据集则是程序在执行过程中所需要使用的资源;进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志。
  
进程是什么
  进程执行程序的最小单位,任务调度采用时间片轮转的抢占式方式进行进程调度。每个进程都有各自的一块独立的内存,保证进程彼此间的内存地址空间的隔离。
  
线程用来解决什么的
   随着计算机技术的发展,进程出现了很多弊端,一是进程的创建、撤销和切换的开销比较大,二是由于对称多处理机(对称多处理机(SymmetricalMulti-Processing)又叫SMP,是指在一个计算机上汇集了一组处理器(多CPU),各CPU之间共享内存子系统以及总线结构)的出现,可以满足多个运行单位,而多进程并行开销过大。

线程什么
  为了解决进程的弊端,引入线程概念, 线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合 和堆栈共同组成。线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能。 线程没有自己的系统资源,只拥有在运行时必不可少的资源。但线程可以与同属与同一进程的其他线程共享进程所拥有的其他资源。

进程与线程之间的关系
   线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。线程可与属于同一进程的其它线程共享进程所拥有的全部资源,但是其本身基本上不拥有系统资源,只拥有一点在运行中必不可少的信息(如程序计数器、一组寄存器和栈)。
协程
  线程和进程的操作是由程序触发系统接口,最后的执行者是系统,它本质上是操作系统提供的功能。而协程的操作则是程序员指定的,在python中通过yield,人为的实现并发处理。
协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时。协程,则只使用一个线程,分解一个线程成为多个“微线程”,在一个线程中规定某个代码块的执行顺序。

协程的适用场景:当程序中存在大量不需要CPU的操作时(IO)。

                         ****进程和线程****
  1. 进程总结
    2.谈谈你对多进程,多线程,以及协程的理解,项目是否用
  2. 什么是多线程竞争
  3. 解释一下什么是锁,有哪几种锁?
  4. 什么是死锁呢?
  5. 什么是线程安全,什么是互斥锁
  6. 说说下面几个概念:同步,异步,阻塞,非阻塞?
  7. 什么是僵尸进程和孤儿进程?怎么避免僵尸进程?
  8. Python 中的进程与线程的使用场景?
    10.线程是并发还是并行,进程是并发还是并行?
    11.并行(parallel)和并发(concurrency)?
    12.IO 密集型和 CPU 密集型区别?
  9. 进程总结
    【刘老师提示:关于这部分内容可参见我发给大家的讲义】
    进程:程序运行在操作系统上的一个实例,就称之为进程。进程需要相应的系统资源:内存、时间片、pid。注意:进程间不共享全局变量。
    创建进程:
    (1)首先要导入 multiprocessing 中的 Process;
    (2)创建一个 Process 对象;
    (3)创建 Process 对象时,可以传递参数;
    (4)使用 start()启动进程;
    (5)结束进程。
    Process 语法结构:
    Process([group [, target [, name [, args [, kwargs]]]]])
    target:如果传递了函数的引用,可以让这个子进程就执行函数中的代码
    args:给 target 指定的函数传递的参数,以元组的形式进行传递
    kwargs:给 target 指定的函数传递参数,以字典的形式进行传递
    name:给进程设定一个名字,可以省略,默认为 Process-N,N 为从 1 开始递增的整数
    group:指定进程组,大多数情况下用不到
    start():启动子进程实例(创建子进程)
    is_alive():判断进程子进程是否还在活着
    join(timeout):是否等待子进程执行结束,或者等待多少秒
    terminate():不管任务是否完成,立即终止子进程
    pid:当前进程的 pid(进程号)
    进程之间的通信-Queue:
    在初始化 Queue()对象时,(例如 q=Queue(),若在括号中没有指定最大可接受的消息数量,或数量为负值时,那么就代表可接受的消息数量没有上限-直到内存的尽头)
    Queue.qsize():返回当前队列包含的消息数量。
    Queue.empty():如果队列为空,返回 True,反之 False。Queue.full():如果队列满了,返回 True,反之 False。
    Queue.get([block[,timeout]]):获取队列中的一条消息,然后将其从队列中移除,block 默认值为True。
    如果 block 使用默认值,且没有设置 timeout(单位秒),消息列队如果为空,此时程序将被阻塞(停在读取状态),直到从消息列队读到消息为止,如果设置了 timeout,则会等待 timeout 秒,若还没读取到任何消息,则抛出"Queue.Empty"异常;
    如果 block 值为 False,消息列队如果为空,则会立刻抛出"Queue.Empty"异常Queue.get_nowait():相当 Queue.get(False);Queue.put(item,[block[, timeout]]):将 item 消息写入队列,block 默认值为 True;
    如果 block 使用默认值,且没有设置 timeout(单位秒),消息列队如果已经没有空间可写入,此时程序将被阻塞(停在写入状态),直到从消息列队腾出空间为止,如果设置了 timeout,则会等待timeout 秒,若还没空间,则抛出"Queue.Full"异常;
    如果 block 值为 False,消息列队如果没有空间可写入,则会立刻出"Queue.Full"异常; Queue.put_nowait(item):相当 Queue.put(item, False);

2.谈谈你对多进程,多线程,以及协程的理解,项目是否用
这个问题被问的概率相当之大,其实多线程,多进程,在实际开发中用到的很少,除非是那些对项目性能要求特别高的,有的开发工作几年了,也确实没用过,你可以这么回答,给他扯扯什么是进程, 线程(cpython 中是伪多线程)的概念就行,实在不行你就说你之前写过下载文件时,用过多线程技术, 或者业余时间用过多线程写爬虫,提升效率。
进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所以进程间数据不共享,(系统资源)开销大。
线程:调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在。一个进程至少有一个线程,叫主线程,而多个线程共享内存(数据共享,共享全局变量),从而极大地提高了程序的运行效率。
协程:是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。 协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

  1. 什么是多线程竞争
    线程是非独立的,同一个进程里线程是数据共享的,当各个线程访问数据资源时会出现竞争状态即: 数据几乎同步会被多个线程占用,造成数据混乱,即所谓的线程不安全
    那么怎么解决多线程竞争问题?-- 锁。
    锁的好处:
    确保了某段关键代码(共享数据资源)只能由一个线程从头到尾完整地执行能解决多线程资源竞争下的原子操作问题。
    锁的坏处:
    阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了锁的致命问题:死锁。

  2. 解释一下什么是锁,有哪几种锁?
    锁(Lock)是 Python 提供的对线程控制的对象。有互斥锁、可重入锁、死锁。

  3. 什么是死锁呢?
    若干子线程在系统资源竞争时,都在等待对方对某部分资源解除占用状态,结果是谁也不愿先解锁, 互相干等着,程序无法执行下去,这就是死锁。
    GIL 锁(有时候,面试官不问,你自己要主动说,增加b格,尽量别一问一答的尬聊,不然最后等到的一句话就是:你还有什么想问的么?)
    GIL 锁 全局解释器锁(只在 cpython 里 才有)
    作用:限制多线程同时执行,保证同一时间只有一个线程执行,所以cpython 里的多线程其实是伪多线程!
    所以 Python 里常常使用协程技术来代替多线程,协程是一种更轻量级的线程,
    进程和线程的切换时由系统决定,而协程由我们程序员自己决定,而模块 gevent 下切换是遇到了耗时操作才会切换。
    三者的关系:进程里有线程,线程里有协程。

  4. 什么是线程安全,什么是互斥锁
    每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
    同一个进程中的多线程之间是共享系统资源的,多个线程同时对一个对象进行操作,一个线程操作尚未结束,另一个线程已经对其进行操作,导致最终结果出现错误,此时需要对被操作对象添加互斥锁, 保证每个线程对该对象的操作都得到正确的结果。

  5. 说说下面几个概念:同步,异步,阻塞,非阻塞?
    同步:多个任务之间有先后顺序执行,一个执行完下个才能执行。
    异步:多个任务之间没有先后顺序,可以同时执行有时候一个任务可能要在必要的时候获取另一个同时执行的任务的结果,这个就叫回调!
    阻塞:如果卡住了调用者,调用者不能继续往下执行,就是说调用者阻塞了。
    非阻塞:如果不会卡住,可以继续执行,就是说非阻塞的。
    同步异步相对于多任务而言,阻塞非阻塞相对于代码执行而言。

  6. 什么是僵尸进程和孤儿进程?怎么避免僵尸进程?
    孤儿进程:父进程退出,子进程还在运行的这些子进程都是孤儿进程,孤儿进程将被 init 进程(进程号为 1)所收养,并由 init 进程对它们完成状态收集工作。
    僵尸进程:进程使用 fork 创建子进程,如果子进程退出,而父进程并没有调用 wait 或 waitpid 获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中的这些进程是僵尸进程。
    避免僵尸进程的方法:
    (1)fork 两次用孙子进程去完成子进程的任务;
    (2)用wait()函数使父进程阻塞;
    (3)使用信号量,在signal handler 中调用 waitpid,这样父进程不用阻塞。

  7. Python 中的进程与线程的使用场景?
    多进程适合在 CPU 密集型操作(cpu 操作指令比较多,如位数多的浮点运算)。多线程适合在 IO 密集型操作(读写数据操作较多的,比如爬虫)。

10.线程是并发还是并行,进程是并发还是并行?
线程是并发,进程是并行;
进程之间相互独立,是系统分配资源的最小单位,同一个线程中的所有线程共享资源。

11.并行(parallel)和并发(concurrency)?
并行:同一时刻多个任务同时在运行。
并发:在同一时间间隔内多个任务都在运行,但是并不会在同一时刻同时运行,存在交替执行的情况。
实现并行的库有:multiprocessing
实现并发的库有:threading
程序需要执行较多的读写、请求和回复任务的需要大量的 IO 操作,IO 密集型操作使用并发更好。
CPU 运算量大的程序程序,使用并行会更好。

12.IO 密集型和 CPU 密集型区别?
IO密集型:系统运作,大部分的状况是 CPU 在等 I/O (硬盘/内存)的读/写。
CPU密集型:大部份时间用来做计算、逻辑判断等 CPU 动作的程序称之CPU密集型。

你可能感兴趣的:(进程 线程 协程)